xref: /netbsd-src/lib/libc/gen/dirname.c (revision d794b9b637e06ef8cce9a4cb2f3ef4c82a40b5f4)
1*d794b9b6Skre /*	$NetBSD: dirname.c,v 1.14 2018/09/27 00:45:34 kre Exp $	*/
28bfc0cefSkleink 
38bfc0cefSkleink /*-
4c10a556fSthorpej  * Copyright (c) 1997, 2002 The NetBSD Foundation, Inc.
58bfc0cefSkleink  * All rights reserved.
68bfc0cefSkleink  *
78bfc0cefSkleink  * This code is derived from software contributed to The NetBSD Foundation
8c10a556fSthorpej  * by Klaus Klein and Jason R. Thorpe.
98bfc0cefSkleink  *
108bfc0cefSkleink  * Redistribution and use in source and binary forms, with or without
118bfc0cefSkleink  * modification, are permitted provided that the following conditions
128bfc0cefSkleink  * are met:
138bfc0cefSkleink  * 1. Redistributions of source code must retain the above copyright
148bfc0cefSkleink  *    notice, this list of conditions and the following disclaimer.
158bfc0cefSkleink  * 2. Redistributions in binary form must reproduce the above copyright
168bfc0cefSkleink  *    notice, this list of conditions and the following disclaimer in the
178bfc0cefSkleink  *    documentation and/or other materials provided with the distribution.
188bfc0cefSkleink  *
198bfc0cefSkleink  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
208bfc0cefSkleink  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
218bfc0cefSkleink  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
228bfc0cefSkleink  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
238bfc0cefSkleink  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
248bfc0cefSkleink  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
258bfc0cefSkleink  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
268bfc0cefSkleink  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
278bfc0cefSkleink  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
288bfc0cefSkleink  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
298bfc0cefSkleink  * POSSIBILITY OF SUCH DAMAGE.
308bfc0cefSkleink  */
318bfc0cefSkleink 
328bfc0cefSkleink #include <sys/cdefs.h>
338bfc0cefSkleink #if defined(LIBC_SCCS) && !defined(lint)
34*d794b9b6Skre __RCSID("$NetBSD: dirname.c,v 1.14 2018/09/27 00:45:34 kre Exp $");
358bfc0cefSkleink #endif /* !LIBC_SCCS && !lint */
368bfc0cefSkleink 
378bfc0cefSkleink #include "namespace.h"
3859925ff2Schristos #include <sys/param.h>
398bfc0cefSkleink #include <libgen.h>
40c10a556fSthorpej #include <limits.h>
419fbd8888Stv #include <string.h>
428bfc0cefSkleink 
438bfc0cefSkleink #ifdef __weak_alias
__weak_alias(dirname,_dirname)4460549036Smycroft __weak_alias(dirname,_dirname)
458bfc0cefSkleink #endif
468bfc0cefSkleink 
4759925ff2Schristos static size_t
48db6e70afSchristos xdirname_r(const char *path, char *buf, size_t buflen)
498bfc0cefSkleink {
5059925ff2Schristos 	const char *endp;
51c10a556fSthorpej 	size_t len;
528bfc0cefSkleink 
538bfc0cefSkleink 	/*
54c10a556fSthorpej 	 * If `path' is a null pointer or points to an empty string,
55c10a556fSthorpej 	 * return a pointer to the string ".".
568bfc0cefSkleink 	 */
5759925ff2Schristos 	if (path == NULL || *path == '\0') {
5859925ff2Schristos 		path = ".";
5959925ff2Schristos 		len = 1;
6059925ff2Schristos 		goto out;
61c10a556fSthorpej 	}
62c10a556fSthorpej 
6359925ff2Schristos 	/* Strip trailing slashes, if any. */
6459925ff2Schristos 	endp = path + strlen(path) - 1;
6559925ff2Schristos 	while (endp != path && *endp == '/')
6659925ff2Schristos 		endp--;
673f8ca7c4Stnozaki 
6859925ff2Schristos 	/* Find the start of the dir */
6959925ff2Schristos 	while (endp > path && *endp != '/')
7059925ff2Schristos 		endp--;
7159925ff2Schristos 
7259925ff2Schristos 	if (endp == path) {
7359925ff2Schristos 		path = *endp == '/' ? "/" : ".";
7459925ff2Schristos 		len = 1;
7559925ff2Schristos 		goto out;
7659925ff2Schristos 	}
7759925ff2Schristos 
7859925ff2Schristos 	do
7959925ff2Schristos 		endp--;
8059925ff2Schristos 	while (endp > path && *endp == '/');
8159925ff2Schristos 
8259925ff2Schristos 	len = endp - path + 1;
8359925ff2Schristos out:
8459925ff2Schristos 	if (buf != NULL && buflen != 0) {
8559925ff2Schristos 		buflen = MIN(len, buflen - 1);
86*d794b9b6Skre 		if (buf != path)
8759925ff2Schristos 			memcpy(buf, path, buflen);
8859925ff2Schristos 		buf[buflen] = '\0';
8959925ff2Schristos 	}
9059925ff2Schristos 	return len;
9159925ff2Schristos }
9259925ff2Schristos 
9359925ff2Schristos #if !HAVE_DIRNAME
9459925ff2Schristos char *
dirname(char * path)9559925ff2Schristos dirname(char *path)
9659925ff2Schristos {
9759925ff2Schristos 	static char result[PATH_MAX];
98db6e70afSchristos 	(void)xdirname_r(path, result, sizeof(result));
9959925ff2Schristos 	return result;
1008bfc0cefSkleink }
101c08a2cb7Stv #endif
102