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