3 * Provides an implementation of the "basename" function, conforming
4 * to SUSv3, with extensions to accommodate Win32 drive designators,
5 * and suitable for use on native Microsoft(R) Win32 platforms.
9 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
10 * Copyright (C) 2006, 2007, 2014, MinGW.org Project
13 * Permission is hereby granted, free of charge, to any person obtaining a
14 * copy of this software and associated documentation files (the "Software"),
15 * to deal in the Software without restriction, including without limitation
16 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 * and/or sell copies of the Software, and to permit persons to whom the
18 * Software is furnished to do so, subject to the following conditions:
20 * The above copyright notice, this permission notice, and the following
21 * disclaimer shall be included in all copies or substantial portions of
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
30 * DEALINGS IN THE SOFTWARE.
39 #ifndef __cdecl /* If compiling on any non-Win32 platform ... */
40 #define __cdecl /* this may not be defined. */
43 __cdecl char *__mingw_basename( char *path )
46 static char *retfail = NULL;
48 /* to handle path names for files in multibyte character locales,
49 * we need to set up LC_CTYPE to match the host file system locale
52 char *locale = setlocale( LC_CTYPE, NULL );
53 if( locale != NULL ) locale = strdup( locale );
54 setlocale( LC_CTYPE, "" );
58 /* allocate sufficient local storage space,
59 * in which to create a wide character reference copy of path
62 wchar_t refcopy[1 + (len = mbstowcs( NULL, path, 0 ))];
64 /* create the wide character reference copy of path,
65 * and step over the drive designator, if present ...
68 wchar_t *refpath = refcopy;
69 if( ((len = mbstowcs( refpath, path, len )) > 1) && (refpath[1] == L':') )
71 /* FIXME: maybe should confirm *refpath is a valid drive designator */
76 /* ensure that our wide character reference path is NUL terminated */
78 refcopy[ len ] = L'\0';
80 /* check again, just to ensure we still have a non-empty path name ... */
84 /* and, when we do, process it in the wide character domain ...
85 * scanning from left to right, to the char after the final dir separator
89 for( refname = refpath ; *refpath ; ++refpath )
91 if( (*refpath == L'/') || (*refpath == L'\\') )
93 /* we found a dir separator ...
94 * step over it, and any others which immediately follow it
97 while( (*refpath == L'/') || (*refpath == L'\\') )
100 /* if we didn't reach the end of the path string ... */
104 /* then we have a new candidate for the base name */
109 * strip off any trailing dir separators which we found
112 else while( (refpath > refname)
113 && ((*--refpath == L'/') || (*refpath == L'\\')) )
118 /* in the wide character domain ...
119 * refname now points at the resolved base name ...
124 /* if it's not empty,
125 * then we transform the full normalised path back into
126 * the multibyte character domain, and skip over the dirname,
127 * to return the resolved basename.
130 if( (len = wcstombs( path, refcopy, len )) != (size_t)(-1) )
133 if( (len = wcstombs( NULL, refcopy, 0 )) != (size_t)(-1) )
139 /* the basename is empty, so return the default value of "/",
140 * transforming from wide char to multibyte char domain, and
141 * returning it in our own buffer.
144 retfail = realloc( retfail, len = 1 + wcstombs( NULL, L"/", 0 ));
145 wcstombs( path = retfail, L"/", len );
148 /* restore the caller's locale, clean up, and return the result */
150 setlocale( LC_CTYPE, locale );
155 /* or we had an empty residual path name, after the drive designator,
156 * in which case we simply fall through ...
160 /* and, if we get to here ...
161 * the path name is either NULL, or it decomposes to an empty string;
162 * in either case, we return the default value of "." in our own buffer,
163 * reloading it with the correct value, transformed from the wide char
164 * to the multibyte char domain, just in case the caller trashed it
165 * after a previous call.
168 retfail = realloc( retfail, len = 1 + wcstombs( NULL, L".", 0 ));
169 wcstombs( retfail, L".", len );
171 /* restore the caller's locale, clean up, and return the result */
173 setlocale( LC_CTYPE, locale );
178 /* $RCSfile$$Revision$: end of file */