/* This code is based on: */ /* $OpenBSD: dirname.c,v 1.12 2005/03/02 12:27:26 millert Exp $ */ /* * Copyright (c) 1997, 2004 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: sm_dirname.c,v 1.2 2005/04/27 23:46:01 ca Exp $") #include "sm/assert.h" #include "sm/error.h" #include "sm/memops.h" #include "sm/misc.h" /* ** SM_DIRNAME -- return directory (or "") of pathname ** (always includes trailing "/" unless empty). ** ** Parameters: ** path -- some path name ** basedir -- directory of path (output) ** baselen -- length of basedir ** ** Returns: ** usual sm_error code */ sm_ret_T sm_dirname(const char *path, char *basedir, size_t baselen) { size_t len; const char *endp; SM_REQUIRE(basedir != NULL); SM_REQUIRE(baselen > 1); basedir[0] = '\0'; /* Empty or NULL string gets treated as "" */ if (path == NULL || *path == '\0') return SM_SUCCESS; /* Strip any trailing slashes */ endp = path + strlen(path) - 1; while (endp > path && *endp == '/') endp--; /* Find the start of the dir */ while (endp > path && *endp != '/') endp--; /* Either the dir is "/" or there are no slashes */ if (endp == path) { if (*endp == '/') { basedir[0] = '/'; basedir[1] = '\0'; } else basedir[0] = '\0'; return SM_SUCCESS; } else { /* Move forward past the separating slashes */ while (endp > path && *endp == '/' && *(endp - 1) == '/') endp--; } len = endp - path + 1; if (len >= baselen) return sm_err_perm(ENAMETOOLONG); sm_memcpy(basedir, path, len); basedir[len] = '\0'; return SM_SUCCESS; }