OSDN Git Service

859a61584bce8e770ed99d9be6f99e208ecd4308
[mingw/mingw-org-wsl.git] / mingwrt / mingwex / basename.c
1 /* basename.c
2  *
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.
6  *
7  * $Id$
8  *
9  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
10  * Copyright (C) 2006, 2007, 2014, MinGW.org Project
11  *
12  *
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:
19  *
20  * The above copyright notice, this permission notice, and the following
21  * disclaimer shall be included in all copies or substantial portions of
22  * the Software.
23  *
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.
31  *
32  */
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <libgen.h>
37 #include <locale.h>
38
39 #ifndef __cdecl  /* If compiling on any non-Win32 platform ... */
40 #define __cdecl  /* this may not be defined.                   */
41 #endif
42
43 __cdecl char *__mingw_basename( char *path )
44 {
45   size_t len;
46   static char *retfail = NULL;
47
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
50    */
51
52   char *locale = setlocale( LC_CTYPE, NULL );
53   if( locale != NULL ) locale = strdup( locale );
54   setlocale( LC_CTYPE, "" );
55
56   if( path && *path )
57   {
58     /* allocate sufficient local storage space,
59      * in which to create a wide character reference copy of path
60      */
61
62     wchar_t refcopy[1 + (len = mbstowcs( NULL, path, 0 ))];
63
64     /* create the wide character reference copy of path,
65      * and step over the drive designator, if present ...
66      */
67
68     wchar_t *refpath = refcopy;
69     if( ((len = mbstowcs( refpath, path, len )) > 1) && (refpath[1] == L':') )
70     {
71       /* FIXME: maybe should confirm *refpath is a valid drive designator */
72
73       refpath += 2;
74     }
75
76     /* ensure that our wide character reference path is NUL terminated */
77
78     refcopy[ len ] = L'\0';
79
80     /* check again, just to ensure we still have a non-empty path name ... */
81
82     if( *refpath )
83     {
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
86        */
87
88       wchar_t *refname;
89       for( refname = refpath ; *refpath ; ++refpath )
90       {
91         if( (*refpath == L'/') || (*refpath == L'\\') )
92         {
93           /* we found a dir separator ...
94            * step over it, and any others which immediately follow it
95            */
96
97           while( (*refpath == L'/') || (*refpath == L'\\') )
98             ++refpath;
99
100           /* if we didn't reach the end of the path string ... */
101
102           if( *refpath )
103
104             /* then we have a new candidate for the base name */
105
106             refname = refpath;
107
108           /* otherwise ...
109            * strip off any trailing dir separators which we found
110            */
111
112           else while(  (refpath > refname)
113           &&          ((*--refpath == L'/') || (*refpath == L'\\'))   )
114             *refpath = L'\0';
115         }
116       }
117
118       /* in the wide character domain ...
119        * refname now points at the resolved base name ...
120        */
121
122       if( *refname )
123       {
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.
128          */
129
130         if( (len = wcstombs( path, refcopy, len )) != (size_t)(-1) )
131           path[ len ] = '\0';
132         *refname = L'\0';
133         if( (len = wcstombs( NULL, refcopy, 0 )) != (size_t)(-1) )
134           path += len;
135       }
136
137       else
138       {
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.
142          */
143
144         retfail = realloc( retfail, len = 1 + wcstombs( NULL, L"/", 0 ));
145         wcstombs( path = retfail, L"/", len );
146       }
147
148       /* restore the caller's locale, clean up, and return the result */
149
150       setlocale( LC_CTYPE, locale );
151       free( locale );
152       return( path );
153     }
154
155     /* or we had an empty residual path name, after the drive designator,
156      * in which case we simply fall through ...
157      */
158   }
159
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.
166    */
167
168   retfail = realloc( retfail, len = 1 + wcstombs( NULL, L".", 0 ));
169   wcstombs( retfail, L".", len );
170
171   /* restore the caller's locale, clean up, and return the result */
172
173   setlocale( LC_CTYPE, locale );
174   free( locale );
175   return( retfail );
176 }
177
178 /* $RCSfile$$Revision$: end of file */