blob c45dbbb3 (4687B) - Raw
1 /* basename.c 2 * 3 * $Id: basename.c,v 1.2 2007/03/08 23:15:58 keithmarshall Exp $ 4 * 5 * Provides an implementation of the "basename" function, conforming 6 * to SUSv3, with extensions to accommodate Win32 drive designators, 7 * and suitable for use on native Microsoft(R) Win32 platforms. 8 * 9 * Written by Keith Marshall <keithmarshall@users.sourceforge.net> 10 * 11 * This is free software. You may redistribute and/or modify it as you 12 * see fit, without restriction of copyright. 13 * 14 * This software is provided "as is", in the hope that it may be useful, 15 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of 16 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no 17 * time will the author accept any form of liability for any damages, 18 * however caused, resulting from the use of this software. 19 * 20 */ 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <libgen.h> 26 #include <locale.h> 27 28 #ifndef __cdecl 29 #define __cdecl 30 #endif 31 32 char * __cdecl 33 basename (char *path) 34 { 35 static char *retfail = NULL; 36 size_t len; 37 /* to handle path names for files in multibyte character locales, 38 * we need to set up LC_CTYPE to match the host file system locale 39 */ 40 char *locale = setlocale (LC_CTYPE, NULL); 41 42 if (locale != NULL) 43 locale = strdup (locale); 44 setlocale (LC_CTYPE, ""); 45 46 if (path && *path) 47 { 48 /* allocate sufficient local storage space, 49 * in which to create a wide character reference copy of path 50 */ 51 wchar_t refcopy[1 + (len = mbstowcs (NULL, path, 0))]; 52 /* create the wide character reference copy of path, 53 * and step over the drive designator, if present ... 54 */ 55 wchar_t *refpath = refcopy; 56 57 if ((len = mbstowcs( refpath, path, len)) > 1 && refpath[1] == L':') 58 { 59 /* FIXME: maybe should confirm *refpath is a valid drive designator */ 60 refpath += 2; 61 } 62 /* ensure that our wide character reference path is NUL terminated */ 63 refcopy[len] = L'\0'; 64 /* check again, just to ensure we still have a non-empty path name ... */ 65 if (*refpath) 66 { 67 /* and, when we do, process it in the wide character domain ... 68 * scanning from left to right, to the char after the final dir separator. */ 69 wchar_t *refname; 70 71 for (refname = refpath; *refpath; ++refpath) 72 { 73 if (*refpath == L'/' || *refpath == L'\\') 74 { 75 /* we found a dir separator ... 76 * step over it, and any others which immediately follow it. */ 77 while (*refpath == L'/' || *refpath == L'\\') 78 ++refpath; 79 /* if we didn't reach the end of the path string ... */ 80 if (*refpath) 81 /* then we have a new candidate for the base name. */ 82 refname = refpath; 83 /* otherwise ... 84 * strip off any trailing dir separators which we found. */ 85 else 86 while (refpath > refname 87 && (*--refpath == L'/' || *refpath == L'\\') ) 88 *refpath = L'\0'; 89 } 90 } 91 /* in the wide character domain ... 92 * refname now points at the resolved base name ... */ 93 if (*refname) 94 { 95 /* if it's not empty, 96 * then we transform the full normalised path back into 97 * the multibyte character domain, and skip over the dirname, 98 * to return the resolved basename. */ 99 if ((len = wcstombs( path, refcopy, len)) != (size_t)(-1)) 100 path[len] = '\0'; 101 *refname = L'\0'; 102 if ((len = wcstombs( NULL, refcopy, 0 )) != (size_t)(-1)) 103 path += len; 104 } 105 else 106 { 107 /* the basename is empty, so return the default value of "/", 108 * transforming from wide char to multibyte char domain, and 109 * returning it in our own buffer. */ 110 retfail = realloc (retfail, len = 1 + wcstombs (NULL, L"/", 0)); 111 wcstombs (path = retfail, L"/", len); 112 } 113 /* restore the caller's locale, clean up, and return the result */ 114 setlocale (LC_CTYPE, locale); 115 free (locale); 116 return path; 117 } 118 /* or we had an empty residual path name, after the drive designator, 119 * in which case we simply fall through ... */ 120 } 121 /* and, if we get to here ... 122 * the path name is either NULL, or it decomposes to an empty string; 123 * in either case, we return the default value of "." in our own buffer, 124 * reloading it with the correct value, transformed from the wide char 125 * to the multibyte char domain, just in case the caller trashed it 126 * after a previous call. 127 */ 128 retfail = realloc (retfail, len = 1 + wcstombs( NULL, L".", 0)); 129 wcstombs (retfail, L".", len); 130 131 /* restore the caller's locale, clean up, and return the result. */ 132 setlocale (LC_CTYPE, locale); 133 free (locale); 134 return retfail; 135 }