/* */
This source file includes following definitions.
- isabspath
- canonpath
- realpath
- makedirectories
- trimpath
1 /*
2 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2008, 2011
3 * Tama Communications Corporation
4 * #ifdef __DJGPP__
5 * Contributed by Jason Hood <jadoxa@yahoo.com.au>, 2001.
6 # #endif
7 *
8 * This file is part of GNU GLOBAL.
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #else
30 #include <strings.h>
31 #endif
32 #include <sys/types.h>
33 #include <sys/stat.h>
34
35 #ifdef __DJGPP__
36 #include <fcntl.h> /* for _USE_LFN */
37 #endif
38
39 #include "gparam.h"
40 #include "path.h"
41 #include "strbuf.h"
42 #include "strlimcpy.h"
43 #include "test.h"
44
45
46 /**
47 * isabspath: whether absolute path or not
48 *
49 * @param[in] p path
50 * @return 1: absolute, 0: not absolute
51 */
52 int
53 isabspath(const char *p)
54 {
55 if (p[0] == '/')
56 return 1;
57 #if defined(_WIN32) || defined(__DJGPP__)
58 if (p[0] == '\\')
59 return 1;
60 if (isdrivechar(p[0]) && p[1] == ':' && (p[2] == '\\' || p[2] == '/'))
61 return 1;
62 #endif
63 return 0;
64 }
65
66 /**
67 * canonpath: make canonical path name.
68 *
69 * @param[in,out] path path
70 * @return path
71 *
72 * @attention canonpath() rewrite argument buffer.
73 */
74 char *
75 canonpath(char *path)
76 {
77 #ifdef __DJGPP__
78 char *p;
79
80 if (_USE_LFN) {
81 char name[260], sfn[13];
82 char *base;
83
84 /*
85 * Ensure we're using a complete long name, not a mixture
86 * of long and short.
87 */
88 _truename(path, path);
89 /*
90 * _truename will successfully convert the path of a non-
91 * existant file, but it's probably still a mixture of long and
92 * short components - convert the path separately.
93 */
94 if (access(path, F_OK) != 0) {
95 base = basename(path);
96 strcpy(name, base);
97 *base = '\0';
98 _truename(path, path);
99 strcat(path, name);
100 }
101 /*
102 * Convert the case of 8.3 names, as other djgpp functions do.
103 */
104 if (!_preserve_fncase()) {
105 for (p = path+3, base = p-1; *base; p++) {
106 if (*p == '\\' || *p == '\0') {
107 memcpy(name, base+1, p-base-1);
108 name[p-base-1] = '\0';
109 if (!strcmp(_lfn_gen_short_fname(name, sfn), name)) {
110 while (++base < p)
111 if (*base >= 'A' && *base <= 'Z')
112 *base += 'a' - 'A';
113 } else
114 base = p;
115 }
116 }
117 }
118 }
119 /*
120 * Lowercase the drive letter and convert to slashes.
121 */
122 path[0] = tolower(path[0]);
123 for (p = path+2; *p; ++p)
124 if (*p == '\\')
125 *p = '/';
126 #else
127 #ifdef _WIN32
128 char *p, *s;
129 p = path;
130 /*
131 * Change \ to / in a path (for DOS/Windows paths)
132 */
133 while ((p = strchr(p, '\\')) != NULL)
134 *p = '/';
135 #ifdef __CYGWIN__
136 /*
137 * On NT with CYGWIN, getcwd can return something like
138 * "//c/tmp", which isn't usable. We change that to "c:/tmp".
139 */
140 p = path;
141 if (p[0] == '/' && p[1] == '/' && isdrivechar(p[2]) && p[3] == '/') {
142 s = &p[2]; /* point drive char */
143 *p++ = *s++;
144 *p++ = ':';
145 while (*p++ = *s++)
146 ;
147 }
148 #endif /* __CYGWIN__ */
149 #endif /* _WIN32 */
150 #endif /* __DJGPP__ */
151 return path;
152 }
153
154 #if (defined(_WIN32) && !defined(__CYGWIN__)) || defined(__DJGPP__)
155 /**
156 * realpath: get the complete path
157 */
158 char *
159 realpath(const char *in_path, char *out_path)
160 {
161 #ifdef __DJGPP__
162 /*
163 * I don't use _fixpath or _truename in LFN because neither guarantee
164 * a complete long name. This is mainly DOS's fault, since the cwd can
165 * be a mixture of long and short components.
166 */
167 if (_USE_LFN) {
168 strlimcpy(out_path, in_path, MAXPATHLEN);
169 canonpath(out_path);
170 } else
171 _fixpath(in_path, out_path);
172 #else
173 _fullpath(out_path, in_path, MAXPATHLEN);
174 canonpath(out_path);
175 #endif
176 return out_path;
177 }
178 #endif
179
180 #define SEP '/'
181
182 /**
183 * makedirectories: make directories on the path like @XREF{mkdir,1} with the @OPTION{-p} option.
184 *
185 * @param[in] base base directory
186 * @param[in] rest path from the base
187 * @param[in] verbose 1: verbose mode, 0: not verbose mode
188 * @return 0: success <br>
189 * -1: base directory not found <br>
190 * -2: permission error <br>
191 * -3: cannot make directory
192 */
193 int
194 makedirectories(const char *base, const char *rest, int verbose)
195 {
196 STRBUF *sb;
197 const char *p, *q;
198
199 if (!test("d", base))
200 return -1;
201 if (!test("drw", base))
202 return -2;
203 sb = strbuf_open(0);
204 strbuf_puts(sb, base);
205 if (*rest == SEP)
206 rest++;
207 for (q = rest; *q;) {
208 p = q;
209 while (*q && *q != SEP)
210 q++;
211 strbuf_putc(sb, SEP);
212 strbuf_nputs(sb, p, q - p);
213 p = strbuf_value(sb);
214 if (!test("d", p)) {
215 if (verbose)
216 fprintf(stderr, " Making directory '%s'.\n", p);
217 #if defined(_WIN32) && !defined(__CYGWIN__)
218 if (mkdir(p) < 0) {
219 #else
220 if (mkdir(p, 0775) < 0) {
221 #endif /* WIN32 */
222 strbuf_close(sb);
223 return -3;
224 }
225 }
226 if (*q == SEP)
227 q++;
228 }
229 strbuf_close(sb);
230 return 0;
231 }
232 /**
233 * trimpath: trim path name
234 */
235 const char *
236 trimpath(const char *path)
237 {
238 if (*path == '.' && *(path + 1) == '/')
239 path += 2;
240 return path;
241 }
/* */