1/*++ 2/* NAME 3/* sane_basename 3 4/* SUMMARY 5/* split pathname into last component and parent directory 6/* SYNOPSIS 7/* #include <stringops.h> 8/* 9/* char *sane_basename(buf, path) 10/* VSTRING *buf; 11/* const char *path; 12/* 13/* char *sane_dirname(buf, path) 14/* VSTRING *buf; 15/* const char *path; 16/* DESCRIPTION 17/* These functions split a pathname into its last component 18/* and its parent directory, excluding any trailing "/" 19/* characters from the input. The result is a pointer to "/" 20/* when the input is all "/" characters, or a pointer to "." 21/* when the input is a null pointer or zero-length string. 22/* 23/* sane_basename() and sane_dirname() differ as follows 24/* from standard basename() and dirname() implementations: 25/* .IP \(bu 26/* They can use caller-provided storage or private storage. 27/* .IP \(bu 28/* They never modify their input. 29/* .PP 30/* sane_basename() returns a pointer to string with the last 31/* pathname component. 32/* 33/* sane_dirname() returns a pointer to string with the parent 34/* directory. The result is a pointer to "." when the input 35/* contains no '/' character. 36/* 37/* Arguments: 38/* .IP buf 39/* Result storage. If a null pointer is specified, each function 40/* uses its own private memory that is overwritten upon each call. 41/* .IP path 42/* The input pathname. 43/* LICENSE 44/* .ad 45/* .fi 46/* The Secure Mailer license must be distributed with this 47/* software. 48/* AUTHOR(S) 49/* Wietse Venema 50/* IBM T.J. Watson Research 51/* P.O. Box 704 52/* Yorktown Heights, NY 10598, USA 53/*--*/ 54 55/* System library. */ 56 57#include <sys_defs.h> 58#include <string.h> 59 60/* Utility library. */ 61 62#include <vstring.h> 63#include <stringops.h> 64 65#define STR(x) vstring_str(x) 66 67/* sane_basename - skip directory prefix */ 68 69char *sane_basename(VSTRING *bp, const char *path) 70{ 71 static VSTRING *buf; 72 const char *first; 73 const char *last; 74 75 /* 76 * Your buffer or mine? 77 */ 78 if (bp == 0) { 79 bp = buf; 80 if (bp == 0) 81 bp = buf = vstring_alloc(10); 82 } 83 84 /* 85 * Special case: return "." for null or zero-length input. 86 */ 87 if (path == 0 || *path == 0) 88 return (STR(vstring_strcpy(bp, "."))); 89 90 /* 91 * Remove trailing '/' characters from input. Return "/" if input is all 92 * '/' characters. 93 */ 94 last = path + strlen(path) - 1; 95 while (*last == '/') { 96 if (last == path) 97 return (STR(vstring_strcpy(bp, "/"))); 98 last--; 99 } 100 101 /* 102 * The pathname does not end in '/'. Skip to last '/' character if any. 103 */ 104 first = last - 1; 105 while (first >= path && *first != '/') 106 first--; 107 108 return (STR(vstring_strncpy(bp, first + 1, last - first))); 109} 110 111/* sane_dirname - keep directory prefix */ 112 113char *sane_dirname(VSTRING *bp, const char *path) 114{ 115 static VSTRING *buf; 116 const char *last; 117 118 /* 119 * Your buffer or mine? 120 */ 121 if (bp == 0) { 122 bp = buf; 123 if (bp == 0) 124 bp = buf = vstring_alloc(10); 125 } 126 127 /* 128 * Special case: return "." for null or zero-length input. 129 */ 130 if (path == 0 || *path == 0) 131 return (STR(vstring_strcpy(bp, "."))); 132 133 /* 134 * Remove trailing '/' characters from input. Return "/" if input is all 135 * '/' characters. 136 */ 137 last = path + strlen(path) - 1; 138 while (*last == '/') { 139 if (last == path) 140 return (STR(vstring_strcpy(bp, "/"))); 141 last--; 142 } 143 144 /* 145 * This pathname does not end in '/'. Skip to last '/' character if any. 146 */ 147 while (last >= path && *last != '/') 148 last--; 149 if (last < path) /* no '/' */ 150 return (STR(vstring_strcpy(bp, "."))); 151 152 /* 153 * Strip trailing '/' characters from dirname (not strictly needed). 154 */ 155 while (last > path && *last == '/') 156 last--; 157 158 return (STR(vstring_strncpy(bp, path, last - path + 1))); 159} 160 161#ifdef TEST 162#include <vstring_vstream.h> 163 164int main(int argc, char **argv) 165{ 166 VSTRING *buf = vstring_alloc(10); 167 char *dir; 168 char *base; 169 170 while (vstring_get_nonl(buf, VSTREAM_IN) > 0) { 171 dir = sane_dirname((VSTRING *) 0, STR(buf)); 172 base = sane_basename((VSTRING *) 0, STR(buf)); 173 vstream_printf("input=\"%s\" dir=\"%s\" base=\"%s\"\n", 174 STR(buf), dir, base); 175 } 176 vstream_fflush(VSTREAM_OUT); 177 vstring_free(buf); 178 return (0); 179} 180 181#endif 182