OSDN Git Service

should include sys/types.h for mode_t
[lha/olha.git] / pathlib.c
1 /*
2   Copyright (c) 2002 Koji Arai
3
4   Permission is hereby granted, free of charge, to any person
5   obtaining a copy of this software and associated documentation files
6   (the "Software"), to deal in the Software without restriction,
7   including without limitation the rights to use, copy, modify, merge,
8   publish, distribute, sublicense, and/or sell copies of the Software,
9   and to permit persons to whom the Software is furnished to do so,
10   subject to the following conditions:
11
12   The above copyright notice and this permission notice shall be
13   included in all copies or substantial portions of the Software.
14
15   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22   SOFTWARE.
23 */
24
25 #include <string.h>
26
27 int
28 path_addsep(char *path, size_t size)
29 {
30     int len = strlen(path);
31
32     if (len > 0 && path[len-1] != '/' && len + 1 < size) {
33         path[len++] = '/';
34         path[len] = 0;
35     }
36
37     return len;
38 }
39
40 char *
41 basename(char *path)
42 {
43     char *p1, *p2;
44     int len;
45
46     len = strlen(path);
47     if (len == 0)
48         return path;
49     if (len == 1 && path[0] == '/')
50         return path;
51     if (path[len-1] == '/')
52         path[len-1] = '\0';
53
54     for (p1 = p2 = path; *p1 != '\0'; p1++) {
55         if (*p1 == '/') {
56             p2 = p1 + 1;
57         }
58     }
59
60     return p2;
61 }
62
63 char *
64 dirname(char *path)
65 {
66     char *p1, *p2;
67     int len;
68
69     len = strlen(path);
70     if (len == 0) {
71         strcpy(path, ".");
72         return path;
73     }
74     if (len == 1 && path[0] == '/')
75         return path;
76     if (path[len-1] == '/')
77         path[len-1] = '\0';
78
79     for (p1 = p2 = path; *p1 != '\0'; p1++) {
80         if (*p1 == '/') {
81             p2 = p1;
82         }
83     }
84     if (*p2 == '/' && p2 == path)
85         p2++;
86     *p2 = '\0';
87
88     if (path[0] == '\0') {
89         strcpy(path, ".");
90         return path;
91     }
92     return path;
93 }
94
95 int
96 makepath(char *dest, int dest_size,
97          char *dir, char *file, char *ext)
98 {
99     int len;
100     char *p;
101     int size;
102
103     p = dest;
104     size = dest_size;
105
106     /* copy directory part */
107     if (dir) {
108         len = string_copy(p, dir, size);
109         size -= len;
110
111         if (len > 0 && size > 0) {
112             if (p[len-1] != '/') {
113                 p[len++] = '/';
114                 size--;
115             }
116         }
117         p += len;
118     }
119
120     /* copy filename part */
121     if (file) {
122         len = string_copy(p, file, size);
123         size -= len;
124         p += len;
125     }
126
127     /* copy suffix part */
128     if (ext) {
129         if (ext[0] != '.' && size > 0) {
130             *(p++) = '.';
131             size--;
132         }
133
134         len = string_copy(p, ext, size);
135         size -= len;
136         p += len;
137     }
138
139     return p - dest;   /* result string length */
140 }
141
142 #include <sys/stat.h>
143 #include <sys/types.h>
144 #include <errno.h>
145
146 int
147 mkdir_p(char *dir, mode_t mode)
148 {
149     int ret;
150
151     if (strcmp(dir, "/") == 0)
152         return 0;
153
154     if (mkdir(dir, mode) == -1) {
155         if (errno == ENOENT) {
156             char *parent = dirname(strdup(dir));
157
158             ret = mkdir_p(parent, mode);
159             free(parent);
160
161             if (ret == -1)
162                 return -1;
163         }
164
165         return mkdir(dir, mode);
166     }
167 }
168
169 int
170 mkdir_parent(char *file)
171 {
172     char *parent;
173     int ret;
174
175     parent = dirname(strdup(file));
176     ret = mkdir_p(parent, 0777);
177     free(parent);
178
179     return ret;
180 }
181
182 #ifdef DEBUG
183
184 #include <stdio.h>
185 #define basename glibc2_basename
186 #include <string.h>             /* strdup() */
187 #undef basename
188
189 #include <assert.h>
190
191 split_path(char *path)
192 {
193     printf("\"%s\"\t= \"%s\" \"%s\"\n",
194            path,
195            dirname(strdup(path)),
196            basename(strdup(path)));
197 }
198
199 main()
200 {
201     char work[256];
202     int len;
203
204     split_path("/foo/bar");
205     split_path("/bar");
206     split_path("bar");
207     split_path("bar/");         /* should print "." and "bar" */
208     split_path("/");            /* should print "/" and "/" */
209     split_path("");             /* should print "." and "" */
210
211
212     len = makepath(work, sizeof work, "foo", "bar", "baz");
213     assert(strcmp(work, "foo/bar.baz") == 0 && len == 11);
214     printf("\"%s\"\n", work);
215
216     len = makepath(work, sizeof work, "foo/", "bar", ".baz");
217     assert(strcmp(work, "foo/bar.baz") == 0 && len == 11);
218     printf("\"%s\"\n", work);
219
220     len = makepath(work, strlen("foo/bar.baz")+1, "foo", "bar", "baz");
221     assert(strcmp(work, "foo/bar.baz") == 0 && len == 11);
222     printf("\"%s\"\n", work);
223
224     len = makepath(work, strlen("foo/bar.baz")+1, "foo", "bar.baz", NULL);
225     assert(strcmp(work, "foo/bar.baz") == 0 && len == 11);
226     printf("\"%s\"\n", work);
227
228     memset(work, '*', sizeof(work)-1);
229     work[sizeof(work)-1] = 0;
230     len = makepath(work+10, sizeof(work)-10, "foo", "bar", "baz");
231     assert(strcmp(work+10, "foo/bar.baz") == 0 && len == 11);
232     printf("\"%s\"\n", work);
233     memset(work+10, '*', strlen("foo/bar.baz")+1);
234     {
235         int i;
236         for (i = 0; i < sizeof(work)-1; i++)
237             assert(work[i] == '*');
238     }
239     printf("\"%s\"\n", work);
240
241     len = makepath(work, strlen("foo/bar.baz"), "foo", "bar", "baz");
242     assert(strcmp(work, "foo/bar.ba") == 0 && len == 10);
243     printf("\"%s\"\n", work);
244
245     return 0;
246 }
247 #endif /* DEBUG */