15796c8dcSSimon Schubert /* File name comparison routine.
25796c8dcSSimon Schubert 
35796c8dcSSimon Schubert    Copyright (C) 2007 Free Software Foundation, Inc.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
65796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
75796c8dcSSimon Schubert    the Free Software Foundation; either version 2, or (at your option)
85796c8dcSSimon Schubert    any later version.
95796c8dcSSimon Schubert 
105796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
115796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
125796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
135796c8dcSSimon Schubert    GNU General Public License for more details.
145796c8dcSSimon Schubert 
155796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
165796c8dcSSimon Schubert    along with this program; if not, write to the Free Software Foundation,
175796c8dcSSimon Schubert    Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
185796c8dcSSimon Schubert 
195796c8dcSSimon Schubert #ifdef HAVE_CONFIG_H
205796c8dcSSimon Schubert #include "config.h"
215796c8dcSSimon Schubert #endif
225796c8dcSSimon Schubert 
235796c8dcSSimon Schubert #ifdef HAVE_STRING_H
245796c8dcSSimon Schubert #include <string.h>
255796c8dcSSimon Schubert #endif
265796c8dcSSimon Schubert 
275796c8dcSSimon Schubert #include "filenames.h"
285796c8dcSSimon Schubert #include "safe-ctype.h"
295796c8dcSSimon Schubert 
305796c8dcSSimon Schubert /*
315796c8dcSSimon Schubert 
325796c8dcSSimon Schubert @deftypefn Extension int filename_cmp (const char *@var{s1}, const char *@var{s2})
335796c8dcSSimon Schubert 
345796c8dcSSimon Schubert Return zero if the two file names @var{s1} and @var{s2} are equivalent.
355796c8dcSSimon Schubert If not equivalent, the returned value is similar to what @code{strcmp}
365796c8dcSSimon Schubert would return.  In other words, it returns a negative value if @var{s1}
375796c8dcSSimon Schubert is less than @var{s2}, or a positive value if @var{s2} is greater than
385796c8dcSSimon Schubert @var{s2}.
395796c8dcSSimon Schubert 
405796c8dcSSimon Schubert This function does not normalize file names.  As a result, this function
415796c8dcSSimon Schubert will treat filenames that are spelled differently as different even in
425796c8dcSSimon Schubert the case when the two filenames point to the same underlying file.
435796c8dcSSimon Schubert However, it does handle the fact that on DOS-like file systems, forward
445796c8dcSSimon Schubert and backward slashes are equal.
455796c8dcSSimon Schubert 
465796c8dcSSimon Schubert @end deftypefn
475796c8dcSSimon Schubert 
485796c8dcSSimon Schubert */
495796c8dcSSimon Schubert 
505796c8dcSSimon Schubert int
filename_cmp(const char * s1,const char * s2)515796c8dcSSimon Schubert filename_cmp (const char *s1, const char *s2)
525796c8dcSSimon Schubert {
53a45ae5f8SJohn Marino #if !defined(HAVE_DOS_BASED_FILE_SYSTEM) \
54a45ae5f8SJohn Marino     && !defined(HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
555796c8dcSSimon Schubert   return strcmp(s1, s2);
565796c8dcSSimon Schubert #else
575796c8dcSSimon Schubert   for (;;)
585796c8dcSSimon Schubert     {
59a45ae5f8SJohn Marino       int c1 = *s1;
60a45ae5f8SJohn Marino       int c2 = *s2;
615796c8dcSSimon Schubert 
62a45ae5f8SJohn Marino #if defined (HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
63a45ae5f8SJohn Marino       c1 = TOLOWER (c1);
64a45ae5f8SJohn Marino       c2 = TOLOWER (c2);
65a45ae5f8SJohn Marino #endif
66a45ae5f8SJohn Marino 
67a45ae5f8SJohn Marino #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
685796c8dcSSimon Schubert       /* On DOS-based file systems, the '/' and the '\' are equivalent.  */
695796c8dcSSimon Schubert       if (c1 == '/')
705796c8dcSSimon Schubert         c1 = '\\';
715796c8dcSSimon Schubert       if (c2 == '/')
725796c8dcSSimon Schubert         c2 = '\\';
73a45ae5f8SJohn Marino #endif
745796c8dcSSimon Schubert 
755796c8dcSSimon Schubert       if (c1 != c2)
765796c8dcSSimon Schubert         return (c1 - c2);
775796c8dcSSimon Schubert 
785796c8dcSSimon Schubert       if (c1 == '\0')
795796c8dcSSimon Schubert         return 0;
805796c8dcSSimon Schubert 
815796c8dcSSimon Schubert       s1++;
825796c8dcSSimon Schubert       s2++;
835796c8dcSSimon Schubert     }
845796c8dcSSimon Schubert #endif
855796c8dcSSimon Schubert }
865796c8dcSSimon Schubert 
87c50c785cSJohn Marino /*
88c50c785cSJohn Marino 
89c50c785cSJohn Marino @deftypefn Extension int filename_ncmp (const char *@var{s1}, const char *@var{s2}, size_t @var{n})
90c50c785cSJohn Marino 
91c50c785cSJohn Marino Return zero if the two file names @var{s1} and @var{s2} are equivalent
92c50c785cSJohn Marino in range @var{n}.
93c50c785cSJohn Marino If not equivalent, the returned value is similar to what @code{strncmp}
94c50c785cSJohn Marino would return.  In other words, it returns a negative value if @var{s1}
95c50c785cSJohn Marino is less than @var{s2}, or a positive value if @var{s2} is greater than
96c50c785cSJohn Marino @var{s2}.
97c50c785cSJohn Marino 
98c50c785cSJohn Marino This function does not normalize file names.  As a result, this function
99c50c785cSJohn Marino will treat filenames that are spelled differently as different even in
100c50c785cSJohn Marino the case when the two filenames point to the same underlying file.
101c50c785cSJohn Marino However, it does handle the fact that on DOS-like file systems, forward
102c50c785cSJohn Marino and backward slashes are equal.
103c50c785cSJohn Marino 
104c50c785cSJohn Marino @end deftypefn
105c50c785cSJohn Marino 
106c50c785cSJohn Marino */
107c50c785cSJohn Marino 
108c50c785cSJohn Marino int
filename_ncmp(const char * s1,const char * s2,size_t n)109c50c785cSJohn Marino filename_ncmp (const char *s1, const char *s2, size_t n)
110c50c785cSJohn Marino {
111a45ae5f8SJohn Marino #if !defined(HAVE_DOS_BASED_FILE_SYSTEM) \
112a45ae5f8SJohn Marino     && !defined(HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
113c50c785cSJohn Marino   return strncmp(s1, s2, n);
114c50c785cSJohn Marino #else
115c50c785cSJohn Marino   if (!n)
116c50c785cSJohn Marino     return 0;
117c50c785cSJohn Marino   for (; n > 0; --n)
118c50c785cSJohn Marino   {
119a45ae5f8SJohn Marino       int c1 = *s1;
120a45ae5f8SJohn Marino       int c2 = *s2;
121c50c785cSJohn Marino 
122a45ae5f8SJohn Marino #if defined (HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
123a45ae5f8SJohn Marino       c1 = TOLOWER (c1);
124a45ae5f8SJohn Marino       c2 = TOLOWER (c2);
125a45ae5f8SJohn Marino #endif
126a45ae5f8SJohn Marino 
127a45ae5f8SJohn Marino #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
128c50c785cSJohn Marino       /* On DOS-based file systems, the '/' and the '\' are equivalent.  */
129c50c785cSJohn Marino       if (c1 == '/')
130c50c785cSJohn Marino         c1 = '\\';
131c50c785cSJohn Marino       if (c2 == '/')
132c50c785cSJohn Marino         c2 = '\\';
133a45ae5f8SJohn Marino #endif
134c50c785cSJohn Marino 
135c50c785cSJohn Marino       if (c1 == '\0' || c1 != c2)
136c50c785cSJohn Marino         return (c1 - c2);
137c50c785cSJohn Marino 
138c50c785cSJohn Marino       s1++;
139c50c785cSJohn Marino       s2++;
140c50c785cSJohn Marino   }
141c50c785cSJohn Marino   return 0;
142c50c785cSJohn Marino #endif
143c50c785cSJohn Marino }
144*ef5ccd6cSJohn Marino 
145*ef5ccd6cSJohn Marino /*
146*ef5ccd6cSJohn Marino 
147*ef5ccd6cSJohn Marino @deftypefn Extension hashval_t filename_hash (const void *@var{s})
148*ef5ccd6cSJohn Marino 
149*ef5ccd6cSJohn Marino Return the hash value for file name @var{s} that will be compared
150*ef5ccd6cSJohn Marino using filename_cmp.
151*ef5ccd6cSJohn Marino This function is for use with hashtab.c hash tables.
152*ef5ccd6cSJohn Marino 
153*ef5ccd6cSJohn Marino @end deftypefn
154*ef5ccd6cSJohn Marino 
155*ef5ccd6cSJohn Marino */
156*ef5ccd6cSJohn Marino 
157*ef5ccd6cSJohn Marino hashval_t
filename_hash(const void * s)158*ef5ccd6cSJohn Marino filename_hash (const void *s)
159*ef5ccd6cSJohn Marino {
160*ef5ccd6cSJohn Marino   /* The cast is for -Wc++-compat.  */
161*ef5ccd6cSJohn Marino   const unsigned char *str = (const unsigned char *) s;
162*ef5ccd6cSJohn Marino   hashval_t r = 0;
163*ef5ccd6cSJohn Marino   unsigned char c;
164*ef5ccd6cSJohn Marino 
165*ef5ccd6cSJohn Marino   while ((c = *str++) != 0)
166*ef5ccd6cSJohn Marino     {
167*ef5ccd6cSJohn Marino       if (c == '\\')
168*ef5ccd6cSJohn Marino 	c = '/';
169*ef5ccd6cSJohn Marino       c = TOLOWER (c);
170*ef5ccd6cSJohn Marino       r = r * 67 + c - 113;
171*ef5ccd6cSJohn Marino     }
172*ef5ccd6cSJohn Marino 
173*ef5ccd6cSJohn Marino   return r;
174*ef5ccd6cSJohn Marino }
175*ef5ccd6cSJohn Marino 
176*ef5ccd6cSJohn Marino /*
177*ef5ccd6cSJohn Marino 
178*ef5ccd6cSJohn Marino @deftypefn Extension int filename_eq (const void *@var{s1}, const void *@var{s2})
179*ef5ccd6cSJohn Marino 
180*ef5ccd6cSJohn Marino Return non-zero if file names @var{s1} and @var{s2} are equivalent.
181*ef5ccd6cSJohn Marino This function is for use with hashtab.c hash tables.
182*ef5ccd6cSJohn Marino 
183*ef5ccd6cSJohn Marino @end deftypefn
184*ef5ccd6cSJohn Marino 
185*ef5ccd6cSJohn Marino */
186*ef5ccd6cSJohn Marino 
187*ef5ccd6cSJohn Marino int
filename_eq(const void * s1,const void * s2)188*ef5ccd6cSJohn Marino filename_eq (const void *s1, const void *s2)
189*ef5ccd6cSJohn Marino {
190*ef5ccd6cSJohn Marino   /* The casts are for -Wc++-compat.  */
191*ef5ccd6cSJohn Marino   return filename_cmp ((const char *) s1, (const char *) s2) == 0;
192*ef5ccd6cSJohn Marino }
193