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