xref: /freebsd/lib/libc/gen/dirname.c (revision e2f68161004f312bf10e4b683ac866b45f6e8489)
1*e2f68161SEd Schouten /*-
2*e2f68161SEd Schouten  * Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
31250db81SDag-Erling Smørgrav  *
4*e2f68161SEd Schouten  * Redistribution and use in source and binary forms, with or without
5*e2f68161SEd Schouten  * modification, are permitted provided that the following conditions
6*e2f68161SEd Schouten  * are met:
7*e2f68161SEd Schouten  * 1. Redistributions of source code must retain the above copyright
8*e2f68161SEd Schouten  *    notice, this list of conditions and the following disclaimer.
9*e2f68161SEd Schouten  * 2. Redistributions in binary form must reproduce the above copyright
10*e2f68161SEd Schouten  *    notice, this list of conditions and the following disclaimer in the
11*e2f68161SEd Schouten  *    documentation and/or other materials provided with the distribution.
121250db81SDag-Erling Smørgrav  *
13*e2f68161SEd Schouten  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14*e2f68161SEd Schouten  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*e2f68161SEd Schouten  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*e2f68161SEd Schouten  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17*e2f68161SEd Schouten  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*e2f68161SEd Schouten  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*e2f68161SEd Schouten  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*e2f68161SEd Schouten  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*e2f68161SEd Schouten  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*e2f68161SEd Schouten  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*e2f68161SEd Schouten  * SUCH DAMAGE.
241250db81SDag-Erling Smørgrav  */
251250db81SDag-Erling Smørgrav 
2656bcbf00SBruce Evans #include <sys/cdefs.h>
27135b57f9SDavid E. O'Brien __FBSDID("$FreeBSD$");
281250db81SDag-Erling Smørgrav 
291250db81SDag-Erling Smørgrav #include <libgen.h>
30*e2f68161SEd Schouten #include <stdbool.h>
311250db81SDag-Erling Smørgrav #include <string.h>
321250db81SDag-Erling Smørgrav 
331250db81SDag-Erling Smørgrav char *
34938809f9SEd Schouten dirname(char *path)
351250db81SDag-Erling Smørgrav {
36*e2f68161SEd Schouten 	const char *in, *prev, *begin, *end;
37*e2f68161SEd Schouten 	char *out;
38*e2f68161SEd Schouten 	size_t prevlen;
39*e2f68161SEd Schouten 	bool skipslash;
401250db81SDag-Erling Smørgrav 
41*e2f68161SEd Schouten 	/*
42*e2f68161SEd Schouten 	 * If path is a null pointer or points to an empty string,
43*e2f68161SEd Schouten 	 * dirname() shall return a pointer to the string ".".
44*e2f68161SEd Schouten 	 */
45*e2f68161SEd Schouten 	if (path == NULL || *path == '\0')
46*e2f68161SEd Schouten 		return ((char *)".");
47*e2f68161SEd Schouten 
48*e2f68161SEd Schouten 	/* Retain at least one leading slash character. */
49*e2f68161SEd Schouten 	in = out = *path == '/' ? path + 1 : path;
50*e2f68161SEd Schouten 
51*e2f68161SEd Schouten 	skipslash = true;
52*e2f68161SEd Schouten 	prev = ".";
53*e2f68161SEd Schouten 	prevlen = 1;
54*e2f68161SEd Schouten 	for (;;) {
55*e2f68161SEd Schouten 		/* Extract the next pathname component. */
56*e2f68161SEd Schouten 		while (*in == '/')
57*e2f68161SEd Schouten 			++in;
58*e2f68161SEd Schouten 		begin = in;
59*e2f68161SEd Schouten 		while (*in != '/' && *in != '\0')
60*e2f68161SEd Schouten 			++in;
61*e2f68161SEd Schouten 		end = in;
62*e2f68161SEd Schouten 		if (begin == end)
63*e2f68161SEd Schouten 			break;
64*e2f68161SEd Schouten 
65*e2f68161SEd Schouten 		/*
66*e2f68161SEd Schouten 		 * Copy over the previous pathname component, except if
67*e2f68161SEd Schouten 		 * it's dot. There is no point in retaining those.
68*e2f68161SEd Schouten 		 */
69*e2f68161SEd Schouten 		if (prevlen != 1 || *prev != '.') {
70*e2f68161SEd Schouten 			if (!skipslash)
71*e2f68161SEd Schouten 				*out++ = '/';
72*e2f68161SEd Schouten 			skipslash = false;
73*e2f68161SEd Schouten 			memmove(out, prev, prevlen);
74*e2f68161SEd Schouten 			out += prevlen;
755fb691beSRob Braun 		}
765fb691beSRob Braun 
77*e2f68161SEd Schouten 		/* Preserve the pathname component for the next iteration. */
78*e2f68161SEd Schouten 		prev = begin;
79*e2f68161SEd Schouten 		prevlen = end - begin;
801250db81SDag-Erling Smørgrav 	}
811250db81SDag-Erling Smørgrav 
82*e2f68161SEd Schouten 	/*
83*e2f68161SEd Schouten 	 * If path does not contain a '/', then dirname() shall return a
84*e2f68161SEd Schouten 	 * pointer to the string ".".
85*e2f68161SEd Schouten 	 */
86*e2f68161SEd Schouten 	if (out == path)
87*e2f68161SEd Schouten 		*out++ = '.';
88*e2f68161SEd Schouten 	*out = '\0';
89*e2f68161SEd Schouten 	return (path);
901250db81SDag-Erling Smørgrav }
91