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