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