12a6b7db3Sskrll /* File name comparison routine.
22a6b7db3Sskrll
3*cb63e24eSchristos Copyright (C) 2007-2024 Free Software Foundation, Inc.
42a6b7db3Sskrll
52a6b7db3Sskrll This program is free software; you can redistribute it and/or modify
62a6b7db3Sskrll it under the terms of the GNU General Public License as published by
72a6b7db3Sskrll the Free Software Foundation; either version 2, or (at your option)
82a6b7db3Sskrll any later version.
92a6b7db3Sskrll
102a6b7db3Sskrll This program is distributed in the hope that it will be useful,
112a6b7db3Sskrll but WITHOUT ANY WARRANTY; without even the implied warranty of
122a6b7db3Sskrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
132a6b7db3Sskrll GNU General Public License for more details.
142a6b7db3Sskrll
152a6b7db3Sskrll You should have received a copy of the GNU General Public License
162a6b7db3Sskrll along with this program; if not, write to the Free Software Foundation,
172a6b7db3Sskrll Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
182a6b7db3Sskrll
192a6b7db3Sskrll #ifdef HAVE_CONFIG_H
202a6b7db3Sskrll #include "config.h"
212a6b7db3Sskrll #endif
222a6b7db3Sskrll
232a6b7db3Sskrll #ifdef HAVE_STRING_H
242a6b7db3Sskrll #include <string.h>
252a6b7db3Sskrll #endif
262a6b7db3Sskrll
279573673dSchristos #ifdef HAVE_STDLIB_H
289573673dSchristos #include <stdlib.h>
299573673dSchristos #endif
309573673dSchristos
312a6b7db3Sskrll #include "filenames.h"
322a6b7db3Sskrll #include "safe-ctype.h"
339573673dSchristos #include "libiberty.h"
342a6b7db3Sskrll
352a6b7db3Sskrll /*
362a6b7db3Sskrll
372a6b7db3Sskrll @deftypefn Extension int filename_cmp (const char *@var{s1}, const char *@var{s2})
382a6b7db3Sskrll
392a6b7db3Sskrll Return zero if the two file names @var{s1} and @var{s2} are equivalent.
402a6b7db3Sskrll If not equivalent, the returned value is similar to what @code{strcmp}
412a6b7db3Sskrll would return. In other words, it returns a negative value if @var{s1}
422a6b7db3Sskrll is less than @var{s2}, or a positive value if @var{s2} is greater than
432a6b7db3Sskrll @var{s2}.
442a6b7db3Sskrll
452a6b7db3Sskrll This function does not normalize file names. As a result, this function
462a6b7db3Sskrll will treat filenames that are spelled differently as different even in
472a6b7db3Sskrll the case when the two filenames point to the same underlying file.
482a6b7db3Sskrll However, it does handle the fact that on DOS-like file systems, forward
492a6b7db3Sskrll and backward slashes are equal.
502a6b7db3Sskrll
512a6b7db3Sskrll @end deftypefn
522a6b7db3Sskrll
532a6b7db3Sskrll */
542a6b7db3Sskrll
552a6b7db3Sskrll int
filename_cmp(const char * s1,const char * s2)562a6b7db3Sskrll filename_cmp (const char *s1, const char *s2)
572a6b7db3Sskrll {
58883529b6Schristos #if !defined(HAVE_DOS_BASED_FILE_SYSTEM) \
59883529b6Schristos && !defined(HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
602a6b7db3Sskrll return strcmp(s1, s2);
612a6b7db3Sskrll #else
622a6b7db3Sskrll for (;;)
632a6b7db3Sskrll {
64883529b6Schristos int c1 = *s1;
65883529b6Schristos int c2 = *s2;
662a6b7db3Sskrll
67883529b6Schristos #if defined (HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
68883529b6Schristos c1 = TOLOWER (c1);
69883529b6Schristos c2 = TOLOWER (c2);
70883529b6Schristos #endif
71883529b6Schristos
72883529b6Schristos #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
732a6b7db3Sskrll /* On DOS-based file systems, the '/' and the '\' are equivalent. */
742a6b7db3Sskrll if (c1 == '/')
752a6b7db3Sskrll c1 = '\\';
762a6b7db3Sskrll if (c2 == '/')
772a6b7db3Sskrll c2 = '\\';
78883529b6Schristos #endif
792a6b7db3Sskrll
802a6b7db3Sskrll if (c1 != c2)
812a6b7db3Sskrll return (c1 - c2);
822a6b7db3Sskrll
832a6b7db3Sskrll if (c1 == '\0')
842a6b7db3Sskrll return 0;
852a6b7db3Sskrll
862a6b7db3Sskrll s1++;
872a6b7db3Sskrll s2++;
882a6b7db3Sskrll }
892a6b7db3Sskrll #endif
902a6b7db3Sskrll }
912a6b7db3Sskrll
92883529b6Schristos /*
93883529b6Schristos
94883529b6Schristos @deftypefn Extension int filename_ncmp (const char *@var{s1}, const char *@var{s2}, size_t @var{n})
95883529b6Schristos
96883529b6Schristos Return zero if the two file names @var{s1} and @var{s2} are equivalent
97883529b6Schristos in range @var{n}.
98883529b6Schristos If not equivalent, the returned value is similar to what @code{strncmp}
99883529b6Schristos would return. In other words, it returns a negative value if @var{s1}
100883529b6Schristos is less than @var{s2}, or a positive value if @var{s2} is greater than
101883529b6Schristos @var{s2}.
102883529b6Schristos
103883529b6Schristos This function does not normalize file names. As a result, this function
104883529b6Schristos will treat filenames that are spelled differently as different even in
105883529b6Schristos the case when the two filenames point to the same underlying file.
106883529b6Schristos However, it does handle the fact that on DOS-like file systems, forward
107883529b6Schristos and backward slashes are equal.
108883529b6Schristos
109883529b6Schristos @end deftypefn
110883529b6Schristos
111883529b6Schristos */
112883529b6Schristos
113883529b6Schristos int
filename_ncmp(const char * s1,const char * s2,size_t n)114883529b6Schristos filename_ncmp (const char *s1, const char *s2, size_t n)
115883529b6Schristos {
116883529b6Schristos #if !defined(HAVE_DOS_BASED_FILE_SYSTEM) \
117883529b6Schristos && !defined(HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
118883529b6Schristos return strncmp(s1, s2, n);
119883529b6Schristos #else
120883529b6Schristos if (!n)
121883529b6Schristos return 0;
122883529b6Schristos for (; n > 0; --n)
123883529b6Schristos {
124883529b6Schristos int c1 = *s1;
125883529b6Schristos int c2 = *s2;
126883529b6Schristos
127883529b6Schristos #if defined (HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
128883529b6Schristos c1 = TOLOWER (c1);
129883529b6Schristos c2 = TOLOWER (c2);
130883529b6Schristos #endif
131883529b6Schristos
132883529b6Schristos #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
133883529b6Schristos /* On DOS-based file systems, the '/' and the '\' are equivalent. */
134883529b6Schristos if (c1 == '/')
135883529b6Schristos c1 = '\\';
136883529b6Schristos if (c2 == '/')
137883529b6Schristos c2 = '\\';
138883529b6Schristos #endif
139883529b6Schristos
140883529b6Schristos if (c1 == '\0' || c1 != c2)
141883529b6Schristos return (c1 - c2);
142883529b6Schristos
143883529b6Schristos s1++;
144883529b6Schristos s2++;
145883529b6Schristos }
146883529b6Schristos return 0;
147883529b6Schristos #endif
148883529b6Schristos }
149883529b6Schristos
150883529b6Schristos /*
151883529b6Schristos
152883529b6Schristos @deftypefn Extension hashval_t filename_hash (const void *@var{s})
153883529b6Schristos
154883529b6Schristos Return the hash value for file name @var{s} that will be compared
155883529b6Schristos using filename_cmp.
156883529b6Schristos This function is for use with hashtab.c hash tables.
157883529b6Schristos
158883529b6Schristos @end deftypefn
159883529b6Schristos
160883529b6Schristos */
161883529b6Schristos
162883529b6Schristos hashval_t
filename_hash(const void * s)163883529b6Schristos filename_hash (const void *s)
164883529b6Schristos {
165883529b6Schristos /* The cast is for -Wc++-compat. */
166883529b6Schristos const unsigned char *str = (const unsigned char *) s;
167883529b6Schristos hashval_t r = 0;
168883529b6Schristos unsigned char c;
169883529b6Schristos
170883529b6Schristos while ((c = *str++) != 0)
171883529b6Schristos {
172883529b6Schristos if (c == '\\')
173883529b6Schristos c = '/';
174883529b6Schristos c = TOLOWER (c);
175883529b6Schristos r = r * 67 + c - 113;
176883529b6Schristos }
177883529b6Schristos
178883529b6Schristos return r;
179883529b6Schristos }
180883529b6Schristos
181883529b6Schristos /*
182883529b6Schristos
183883529b6Schristos @deftypefn Extension int filename_eq (const void *@var{s1}, const void *@var{s2})
184883529b6Schristos
185883529b6Schristos Return non-zero if file names @var{s1} and @var{s2} are equivalent.
186883529b6Schristos This function is for use with hashtab.c hash tables.
187883529b6Schristos
188883529b6Schristos @end deftypefn
189883529b6Schristos
190883529b6Schristos */
191883529b6Schristos
192883529b6Schristos int
filename_eq(const void * s1,const void * s2)193883529b6Schristos filename_eq (const void *s1, const void *s2)
194883529b6Schristos {
195883529b6Schristos /* The casts are for -Wc++-compat. */
196883529b6Schristos return filename_cmp ((const char *) s1, (const char *) s2) == 0;
197883529b6Schristos }
1989573673dSchristos
1999573673dSchristos /*
2009573673dSchristos
2019573673dSchristos @deftypefn Extension int canonical_filename_eq (const char *@var{a}, const char *@var{b})
2029573673dSchristos
2039573673dSchristos Return non-zero if file names @var{a} and @var{b} are equivalent.
2049573673dSchristos This function compares the canonical versions of the filenames as returned by
2059573673dSchristos @code{lrealpath()}, so that so that different file names pointing to the same
2069573673dSchristos underlying file are treated as being identical.
2079573673dSchristos
2089573673dSchristos @end deftypefn
2099573673dSchristos
2109573673dSchristos */
2119573673dSchristos
2129573673dSchristos int
canonical_filename_eq(const char * a,const char * b)2139573673dSchristos canonical_filename_eq (const char * a, const char * b)
2149573673dSchristos {
2159573673dSchristos char * ca = lrealpath(a);
2169573673dSchristos char * cb = lrealpath(b);
2179573673dSchristos int res = filename_eq (ca, cb);
2189573673dSchristos free (ca);
2199573673dSchristos free (cb);
2209573673dSchristos return res;
2219573673dSchristos }
222