1*a9fa9459Szrj /* File name comparison routine.
2*a9fa9459Szrj 
3*a9fa9459Szrj    Copyright (C) 2007 Free Software Foundation, Inc.
4*a9fa9459Szrj 
5*a9fa9459Szrj    This program is free software; you can redistribute it and/or modify
6*a9fa9459Szrj    it under the terms of the GNU General Public License as published by
7*a9fa9459Szrj    the Free Software Foundation; either version 2, or (at your option)
8*a9fa9459Szrj    any later version.
9*a9fa9459Szrj 
10*a9fa9459Szrj    This program is distributed in the hope that it will be useful,
11*a9fa9459Szrj    but WITHOUT ANY WARRANTY; without even the implied warranty of
12*a9fa9459Szrj    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*a9fa9459Szrj    GNU General Public License for more details.
14*a9fa9459Szrj 
15*a9fa9459Szrj    You should have received a copy of the GNU General Public License
16*a9fa9459Szrj    along with this program; if not, write to the Free Software Foundation,
17*a9fa9459Szrj    Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
18*a9fa9459Szrj 
19*a9fa9459Szrj #ifdef HAVE_CONFIG_H
20*a9fa9459Szrj #include "config.h"
21*a9fa9459Szrj #endif
22*a9fa9459Szrj 
23*a9fa9459Szrj #ifdef HAVE_STRING_H
24*a9fa9459Szrj #include <string.h>
25*a9fa9459Szrj #endif
26*a9fa9459Szrj 
27*a9fa9459Szrj #ifdef HAVE_STDLIB_H
28*a9fa9459Szrj #include <stdlib.h>
29*a9fa9459Szrj #endif
30*a9fa9459Szrj 
31*a9fa9459Szrj #include "filenames.h"
32*a9fa9459Szrj #include "safe-ctype.h"
33*a9fa9459Szrj #include "libiberty.h"
34*a9fa9459Szrj 
35*a9fa9459Szrj /*
36*a9fa9459Szrj 
37*a9fa9459Szrj @deftypefn Extension int filename_cmp (const char *@var{s1}, const char *@var{s2})
38*a9fa9459Szrj 
39*a9fa9459Szrj Return zero if the two file names @var{s1} and @var{s2} are equivalent.
40*a9fa9459Szrj If not equivalent, the returned value is similar to what @code{strcmp}
41*a9fa9459Szrj would return.  In other words, it returns a negative value if @var{s1}
42*a9fa9459Szrj is less than @var{s2}, or a positive value if @var{s2} is greater than
43*a9fa9459Szrj @var{s2}.
44*a9fa9459Szrj 
45*a9fa9459Szrj This function does not normalize file names.  As a result, this function
46*a9fa9459Szrj will treat filenames that are spelled differently as different even in
47*a9fa9459Szrj the case when the two filenames point to the same underlying file.
48*a9fa9459Szrj However, it does handle the fact that on DOS-like file systems, forward
49*a9fa9459Szrj and backward slashes are equal.
50*a9fa9459Szrj 
51*a9fa9459Szrj @end deftypefn
52*a9fa9459Szrj 
53*a9fa9459Szrj */
54*a9fa9459Szrj 
55*a9fa9459Szrj int
filename_cmp(const char * s1,const char * s2)56*a9fa9459Szrj filename_cmp (const char *s1, const char *s2)
57*a9fa9459Szrj {
58*a9fa9459Szrj #if !defined(HAVE_DOS_BASED_FILE_SYSTEM) \
59*a9fa9459Szrj     && !defined(HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
60*a9fa9459Szrj   return strcmp(s1, s2);
61*a9fa9459Szrj #else
62*a9fa9459Szrj   for (;;)
63*a9fa9459Szrj     {
64*a9fa9459Szrj       int c1 = *s1;
65*a9fa9459Szrj       int c2 = *s2;
66*a9fa9459Szrj 
67*a9fa9459Szrj #if defined (HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
68*a9fa9459Szrj       c1 = TOLOWER (c1);
69*a9fa9459Szrj       c2 = TOLOWER (c2);
70*a9fa9459Szrj #endif
71*a9fa9459Szrj 
72*a9fa9459Szrj #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
73*a9fa9459Szrj       /* On DOS-based file systems, the '/' and the '\' are equivalent.  */
74*a9fa9459Szrj       if (c1 == '/')
75*a9fa9459Szrj         c1 = '\\';
76*a9fa9459Szrj       if (c2 == '/')
77*a9fa9459Szrj         c2 = '\\';
78*a9fa9459Szrj #endif
79*a9fa9459Szrj 
80*a9fa9459Szrj       if (c1 != c2)
81*a9fa9459Szrj         return (c1 - c2);
82*a9fa9459Szrj 
83*a9fa9459Szrj       if (c1 == '\0')
84*a9fa9459Szrj         return 0;
85*a9fa9459Szrj 
86*a9fa9459Szrj       s1++;
87*a9fa9459Szrj       s2++;
88*a9fa9459Szrj     }
89*a9fa9459Szrj #endif
90*a9fa9459Szrj }
91*a9fa9459Szrj 
92*a9fa9459Szrj /*
93*a9fa9459Szrj 
94*a9fa9459Szrj @deftypefn Extension int filename_ncmp (const char *@var{s1}, const char *@var{s2}, size_t @var{n})
95*a9fa9459Szrj 
96*a9fa9459Szrj Return zero if the two file names @var{s1} and @var{s2} are equivalent
97*a9fa9459Szrj in range @var{n}.
98*a9fa9459Szrj If not equivalent, the returned value is similar to what @code{strncmp}
99*a9fa9459Szrj would return.  In other words, it returns a negative value if @var{s1}
100*a9fa9459Szrj is less than @var{s2}, or a positive value if @var{s2} is greater than
101*a9fa9459Szrj @var{s2}.
102*a9fa9459Szrj 
103*a9fa9459Szrj This function does not normalize file names.  As a result, this function
104*a9fa9459Szrj will treat filenames that are spelled differently as different even in
105*a9fa9459Szrj the case when the two filenames point to the same underlying file.
106*a9fa9459Szrj However, it does handle the fact that on DOS-like file systems, forward
107*a9fa9459Szrj and backward slashes are equal.
108*a9fa9459Szrj 
109*a9fa9459Szrj @end deftypefn
110*a9fa9459Szrj 
111*a9fa9459Szrj */
112*a9fa9459Szrj 
113*a9fa9459Szrj int
filename_ncmp(const char * s1,const char * s2,size_t n)114*a9fa9459Szrj filename_ncmp (const char *s1, const char *s2, size_t n)
115*a9fa9459Szrj {
116*a9fa9459Szrj #if !defined(HAVE_DOS_BASED_FILE_SYSTEM) \
117*a9fa9459Szrj     && !defined(HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
118*a9fa9459Szrj   return strncmp(s1, s2, n);
119*a9fa9459Szrj #else
120*a9fa9459Szrj   if (!n)
121*a9fa9459Szrj     return 0;
122*a9fa9459Szrj   for (; n > 0; --n)
123*a9fa9459Szrj   {
124*a9fa9459Szrj       int c1 = *s1;
125*a9fa9459Szrj       int c2 = *s2;
126*a9fa9459Szrj 
127*a9fa9459Szrj #if defined (HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
128*a9fa9459Szrj       c1 = TOLOWER (c1);
129*a9fa9459Szrj       c2 = TOLOWER (c2);
130*a9fa9459Szrj #endif
131*a9fa9459Szrj 
132*a9fa9459Szrj #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
133*a9fa9459Szrj       /* On DOS-based file systems, the '/' and the '\' are equivalent.  */
134*a9fa9459Szrj       if (c1 == '/')
135*a9fa9459Szrj         c1 = '\\';
136*a9fa9459Szrj       if (c2 == '/')
137*a9fa9459Szrj         c2 = '\\';
138*a9fa9459Szrj #endif
139*a9fa9459Szrj 
140*a9fa9459Szrj       if (c1 == '\0' || c1 != c2)
141*a9fa9459Szrj         return (c1 - c2);
142*a9fa9459Szrj 
143*a9fa9459Szrj       s1++;
144*a9fa9459Szrj       s2++;
145*a9fa9459Szrj   }
146*a9fa9459Szrj   return 0;
147*a9fa9459Szrj #endif
148*a9fa9459Szrj }
149*a9fa9459Szrj 
150*a9fa9459Szrj /*
151*a9fa9459Szrj 
152*a9fa9459Szrj @deftypefn Extension hashval_t filename_hash (const void *@var{s})
153*a9fa9459Szrj 
154*a9fa9459Szrj Return the hash value for file name @var{s} that will be compared
155*a9fa9459Szrj using filename_cmp.
156*a9fa9459Szrj This function is for use with hashtab.c hash tables.
157*a9fa9459Szrj 
158*a9fa9459Szrj @end deftypefn
159*a9fa9459Szrj 
160*a9fa9459Szrj */
161*a9fa9459Szrj 
162*a9fa9459Szrj hashval_t
filename_hash(const void * s)163*a9fa9459Szrj filename_hash (const void *s)
164*a9fa9459Szrj {
165*a9fa9459Szrj   /* The cast is for -Wc++-compat.  */
166*a9fa9459Szrj   const unsigned char *str = (const unsigned char *) s;
167*a9fa9459Szrj   hashval_t r = 0;
168*a9fa9459Szrj   unsigned char c;
169*a9fa9459Szrj 
170*a9fa9459Szrj   while ((c = *str++) != 0)
171*a9fa9459Szrj     {
172*a9fa9459Szrj       if (c == '\\')
173*a9fa9459Szrj 	c = '/';
174*a9fa9459Szrj       c = TOLOWER (c);
175*a9fa9459Szrj       r = r * 67 + c - 113;
176*a9fa9459Szrj     }
177*a9fa9459Szrj 
178*a9fa9459Szrj   return r;
179*a9fa9459Szrj }
180*a9fa9459Szrj 
181*a9fa9459Szrj /*
182*a9fa9459Szrj 
183*a9fa9459Szrj @deftypefn Extension int filename_eq (const void *@var{s1}, const void *@var{s2})
184*a9fa9459Szrj 
185*a9fa9459Szrj Return non-zero if file names @var{s1} and @var{s2} are equivalent.
186*a9fa9459Szrj This function is for use with hashtab.c hash tables.
187*a9fa9459Szrj 
188*a9fa9459Szrj @end deftypefn
189*a9fa9459Szrj 
190*a9fa9459Szrj */
191*a9fa9459Szrj 
192*a9fa9459Szrj int
filename_eq(const void * s1,const void * s2)193*a9fa9459Szrj filename_eq (const void *s1, const void *s2)
194*a9fa9459Szrj {
195*a9fa9459Szrj   /* The casts are for -Wc++-compat.  */
196*a9fa9459Szrj   return filename_cmp ((const char *) s1, (const char *) s2) == 0;
197*a9fa9459Szrj }
198*a9fa9459Szrj 
199*a9fa9459Szrj /*
200*a9fa9459Szrj 
201*a9fa9459Szrj @deftypefn Extension int canonical_filename_eq (const char *@var{a}, const char *@var{b})
202*a9fa9459Szrj 
203*a9fa9459Szrj Return non-zero if file names @var{a} and @var{b} are equivalent.
204*a9fa9459Szrj This function compares the canonical versions of the filenames as returned by
205*a9fa9459Szrj @code{lrealpath()}, so that so that different file names pointing to the same
206*a9fa9459Szrj underlying file are treated as being identical.
207*a9fa9459Szrj 
208*a9fa9459Szrj @end deftypefn
209*a9fa9459Szrj 
210*a9fa9459Szrj */
211*a9fa9459Szrj 
212*a9fa9459Szrj int
canonical_filename_eq(const char * a,const char * b)213*a9fa9459Szrj canonical_filename_eq (const char * a, const char * b)
214*a9fa9459Szrj {
215*a9fa9459Szrj   char * ca = lrealpath(a);
216*a9fa9459Szrj   char * cb = lrealpath(b);
217*a9fa9459Szrj   int res = filename_eq (ca, cb);
218*a9fa9459Szrj   free (ca);
219*a9fa9459Szrj   free (cb);
220*a9fa9459Szrj   return res;
221*a9fa9459Szrj }
222