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