1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
16 /* Initial buffer size for getcwd */
19 expstring_t
get_working_dir(void)
21 expstring_t ret_val
= NULL
;
24 buf_ptr
= getcwd(buf
, sizeof(buf
));
25 if (buf_ptr
!= NULL
) ret_val
= mcopystr(buf_ptr
);
26 else if (errno
== ERANGE
) {
27 /* the initial buffer size is not enough */
29 for (size
= 2 * BUFSIZE
; ; size
*= 2) {
30 char *tmp
= (char*)Malloc(size
);
31 buf_ptr
= getcwd(tmp
, size
);
32 if (buf_ptr
!= NULL
) ret_val
= mcopystr(buf_ptr
);
34 if (buf_ptr
!= NULL
|| errno
!= ERANGE
) break;
37 if (ret_val
== NULL
) {
38 /* an error occurred */
39 path_error("Getting the current working directory failed: %s",
42 /* clear the possible error codes */
47 int set_working_dir(const char *new_dir
)
49 if (new_dir
== NULL
) {
50 /* invalid argument */
52 } else if (chdir(new_dir
)) {
53 /* an error occurred */
54 path_error("Setting the current working directory to `%s' failed: %s",
55 new_dir
, strerror(errno
));
59 /* everything is OK */
64 enum path_status_t
get_path_status(const char *path_name
)
67 if (stat(path_name
, &buf
)) {
68 if (errno
!= ENOENT
) {
69 path_error("system call stat() failed on `%s': %s", path_name
,
73 return PS_NONEXISTENT
;
75 if (S_ISDIR(buf
.st_mode
)) return PS_DIRECTORY
;
79 expstring_t
get_dir_from_path(const char *path_name
)
81 size_t last_slash_index
= (size_t)-1;
83 for (i
= 0; path_name
[i
] != '\0'; i
++)
84 if (path_name
[i
] == '/') last_slash_index
= i
;
85 if (last_slash_index
== (size_t)-1) {
86 /* path_name does not contain any slash */
88 } else if (last_slash_index
== 0) {
89 /* path_name has the format "/filename": return "/" */
92 /* path_name has the format "<something>/filename":
93 return "<something>" */
94 expstring_t ret_val
= mcopystr(path_name
);
95 ret_val
= mtruncstr(ret_val
, last_slash_index
);
100 expstring_t
get_file_from_path(const char *path_name
)
102 size_t last_slash_index
= (size_t)-1;
104 for (i
= 0; path_name
[i
] != '\0'; i
++)
105 if (path_name
[i
] == '/') last_slash_index
= i
;
106 if (last_slash_index
== (size_t)-1) {
107 /* path_name does not contain any slash: return the entire input */
108 return mcopystr(path_name
);
110 /* path_name has the format "<something>/filename": return "filename" */
111 return mcopystr(path_name
+ last_slash_index
+ 1);
115 expstring_t
compose_path_name(const char *dir_name
,
116 const char *file_name
)
118 if (dir_name
!= NULL
&& dir_name
[0] != '\0') {
119 expstring_t ret_val
= mcopystr(dir_name
);
120 if (file_name
!= NULL
&& file_name
[0] != '\0') {
121 /* neither dir_name nor file_name are empty */
122 size_t dir_name_len
= strlen(dir_name
);
123 /* do not add the separator slash if dir_name ends with a slash */
124 if (dir_name
[dir_name_len
- 1] != '/')
125 ret_val
= mputc(ret_val
, '/');
126 ret_val
= mputstr(ret_val
, file_name
);
129 } else return mcopystr(file_name
);
132 expstring_t
get_absolute_dir(const char *dir_name
, const char *base_dir
)
135 /* save the working directory */
136 expstring_t initial_dir
= get_working_dir();
137 if (base_dir
!= NULL
&& (dir_name
== NULL
|| dir_name
[0] != '/')) {
138 /* go to base_dir first if it is given and dir_name is not an
140 if (set_working_dir(base_dir
)) {
145 if (dir_name
!= NULL
&& set_working_dir(dir_name
)) {
146 /* there was an error: go back to initial_dir */
147 set_working_dir(initial_dir
);
151 ret_val
= get_working_dir();
152 /* restore the working directory */
153 set_working_dir(initial_dir
);
155 if (ret_val
!= NULL
&&
156 #if defined WIN32 && defined MINGW
157 /* On native Windows the absolute path name shall begin with
158 * a drive letter, colon and backslash */
159 (((ret_val
[0] < 'A' || ret_val
[0] > 'Z') &&
160 (ret_val
[0] < 'a' || ret_val
[0] > 'z')) ||
161 ret_val
[1] != ':' || ret_val
[2] != '\\')
163 /* On UNIX-like systems the absolute path name shall begin with
168 path_error("Internal error: `%s' is not a valid absolute pathname.",
173 expstring_t
get_relative_dir(const char *dir_name
, const char *base_dir
)
175 expstring_t ret_val
= NULL
;
176 /* canonize dir_name and the base directory */
177 expstring_t canonized_dir_name
= get_absolute_dir(dir_name
, base_dir
);
178 expstring_t canonized_base_dir
= base_dir
!= NULL
?
179 get_absolute_dir(base_dir
, NULL
) : get_working_dir();
180 size_t i
, last_slash
= 0;
181 if (canonized_dir_name
== NULL
|| canonized_base_dir
== NULL
) {
182 /* an error occurred */
183 Free(canonized_dir_name
);
184 Free(canonized_base_dir
);
187 /* skip over the common leading directory part of canonized_dir_name and
188 canonized_base_dir */
190 char dir_c
= canonized_dir_name
[i
];
191 char base_c
= canonized_base_dir
[i
];
193 /* we must update last_slash if dir_name is a parent of base_dir */
194 if (base_c
== '/') last_slash
= i
;
195 /* we must stop anyway */
197 } else if (dir_c
== '/') {
198 if (base_c
== '/' || base_c
== '\0') last_slash
= i
;
199 if (base_c
!= '/') break;
201 if (dir_c
!= base_c
) break;
204 if (canonized_dir_name
[i
] == '\0' && canonized_base_dir
[i
] == '\0') {
205 /* canonized_dir_name and canonized_base_dir are the same */
206 ret_val
= mcopystr(".");
208 if (canonized_base_dir
[last_slash
] == '/' &&
209 canonized_base_dir
[last_slash
+ 1] != '\0') {
210 /* canonized_base_dir has some own additional components
211 (i.e. it is not the parent of canonized_dir_name) */
212 for (i
= last_slash
; canonized_base_dir
[i
] != '\0'; i
++) {
213 if (canonized_base_dir
[i
] == '/') {
214 /* go up one level in the relative path */
215 if (ret_val
!= NULL
) ret_val
= mputc(ret_val
, '/');
216 ret_val
= mputstr(ret_val
, "..");
220 if (canonized_dir_name
[last_slash
] == '/' &&
221 canonized_dir_name
[last_slash
+ 1] != '\0') {
222 /* canonized_dir_name has some own additional components
223 (i.e. it is not the parent of canonized_base_dir) */
224 /* append the remaining parts of canonized_dir_name to the result */
225 if (ret_val
!= NULL
) ret_val
= mputc(ret_val
, '/');
226 ret_val
= mputstr(ret_val
, canonized_dir_name
+ last_slash
+ 1);
229 Free(canonized_dir_name
);
230 Free(canonized_base_dir
);