xref: /netbsd-src/external/gpl3/binutils/dist/libiberty/filename_cmp.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
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