1 /******************************************************************************
2 * Copyright (c) 2000-2016 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
13 * Szabo, Janos Zoltan – initial implementation
15 ******************************************************************************/
24 /* Initial buffer size for getcwd */
27 expstring_t
get_working_dir(void)
29 expstring_t ret_val
= NULL
;
32 buf_ptr
= getcwd(buf
, sizeof(buf
));
33 if (buf_ptr
!= NULL
) ret_val
= mcopystr(buf_ptr
);
34 else if (errno
== ERANGE
) {
35 /* the initial buffer size is not enough */
37 for (size
= 2 * BUFSIZE
; ; size
*= 2) {
38 char *tmp
= (char*)Malloc(size
);
39 buf_ptr
= getcwd(tmp
, size
);
40 if (buf_ptr
!= NULL
) ret_val
= mcopystr(buf_ptr
);
42 if (buf_ptr
!= NULL
|| errno
!= ERANGE
) break;
45 if (ret_val
== NULL
) {
46 /* an error occurred */
47 path_error("Getting the current working directory failed: %s",
50 /* clear the possible error codes */
55 int set_working_dir(const char *new_dir
)
57 if (new_dir
== NULL
) {
58 /* invalid argument */
60 } else if (chdir(new_dir
)) {
61 /* an error occurred */
62 path_error("Setting the current working directory to `%s' failed: %s",
63 new_dir
, strerror(errno
));
67 /* everything is OK */
72 enum path_status_t
get_path_status(const char *path_name
)
75 if (stat(path_name
, &buf
)) {
76 if (errno
!= ENOENT
) {
77 path_error("system call stat() failed on `%s': %s", path_name
,
81 return PS_NONEXISTENT
;
83 if (S_ISDIR(buf
.st_mode
)) return PS_DIRECTORY
;
87 expstring_t
get_dir_from_path(const char *path_name
)
89 size_t last_slash_index
= (size_t)-1;
91 for (i
= 0; path_name
[i
] != '\0'; i
++)
92 if (path_name
[i
] == '/') last_slash_index
= i
;
93 if (last_slash_index
== (size_t)-1) {
94 /* path_name does not contain any slash */
96 } else if (last_slash_index
== 0) {
97 /* path_name has the format "/filename": return "/" */
100 /* path_name has the format "<something>/filename":
101 return "<something>" */
102 expstring_t ret_val
= mcopystr(path_name
);
103 ret_val
= mtruncstr(ret_val
, last_slash_index
);
108 expstring_t
get_file_from_path(const char *path_name
)
110 size_t last_slash_index
= (size_t)-1;
112 for (i
= 0; path_name
[i
] != '\0'; i
++)
113 if (path_name
[i
] == '/') last_slash_index
= i
;
114 if (last_slash_index
== (size_t)-1) {
115 /* path_name does not contain any slash: return the entire input */
116 return mcopystr(path_name
);
118 /* path_name has the format "<something>/filename": return "filename" */
119 return mcopystr(path_name
+ last_slash_index
+ 1);
123 expstring_t
compose_path_name(const char *dir_name
,
124 const char *file_name
)
126 if (dir_name
!= NULL
&& dir_name
[0] != '\0') {
127 expstring_t ret_val
= mcopystr(dir_name
);
128 if (file_name
!= NULL
&& file_name
[0] != '\0') {
129 /* neither dir_name nor file_name are empty */
130 size_t dir_name_len
= strlen(dir_name
);
131 /* do not add the separator slash if dir_name ends with a slash */
132 if (dir_name
[dir_name_len
- 1] != '/')
133 ret_val
= mputc(ret_val
, '/');
134 ret_val
= mputstr(ret_val
, file_name
);
137 } else return mcopystr(file_name
);
140 expstring_t
get_absolute_dir(const char *dir_name
, const char *base_dir
, const int with_error
)
143 /* save the working directory */
144 expstring_t initial_dir
= get_working_dir();
145 if (base_dir
!= NULL
&& (dir_name
== NULL
|| dir_name
[0] != '/')) {
146 /* go to base_dir first if it is given and dir_name is not an
148 if (set_working_dir(base_dir
)) {
153 if (dir_name
!= NULL
&& with_error
&& set_working_dir(dir_name
)) {
154 /* there was an error: go back to initial_dir */
155 set_working_dir(initial_dir
);
159 if (dir_name
!= NULL
&& !with_error
&& chdir(dir_name
)) {
165 ret_val
= get_working_dir();
166 /* restore the working directory */
167 set_working_dir(initial_dir
);
169 if (ret_val
!= NULL
&&
170 #if defined WIN32 && defined MINGW
171 /* On native Windows the absolute path name shall begin with
172 * a drive letter, colon and backslash */
173 (((ret_val
[0] < 'A' || ret_val
[0] > 'Z') &&
174 (ret_val
[0] < 'a' || ret_val
[0] > 'z')) ||
175 ret_val
[1] != ':' || ret_val
[2] != '\\')
177 /* On UNIX-like systems the absolute path name shall begin with
182 path_error("Internal error: `%s' is not a valid absolute pathname.",
187 expstring_t
get_relative_dir(const char *dir_name
, const char *base_dir
)
189 expstring_t ret_val
= NULL
;
190 /* canonize dir_name and the base directory */
191 expstring_t canonized_dir_name
= get_absolute_dir(dir_name
, base_dir
, 1);
192 expstring_t canonized_base_dir
= base_dir
!= NULL
?
193 get_absolute_dir(base_dir
, NULL
, 1) : get_working_dir();
194 size_t i
, last_slash
= 0;
195 if (canonized_dir_name
== NULL
|| canonized_base_dir
== NULL
) {
196 /* an error occurred */
197 Free(canonized_dir_name
);
198 Free(canonized_base_dir
);
201 /* skip over the common leading directory part of canonized_dir_name and
202 canonized_base_dir */
204 char dir_c
= canonized_dir_name
[i
];
205 char base_c
= canonized_base_dir
[i
];
207 /* we must update last_slash if dir_name is a parent of base_dir */
208 if (base_c
== '/') last_slash
= i
;
209 /* we must stop anyway */
211 } else if (dir_c
== '/') {
212 if (base_c
== '/' || base_c
== '\0') last_slash
= i
;
213 if (base_c
!= '/') break;
215 if (dir_c
!= base_c
) break;
218 if (canonized_dir_name
[i
] == '\0' && canonized_base_dir
[i
] == '\0') {
219 /* canonized_dir_name and canonized_base_dir are the same */
220 ret_val
= mcopystr(".");
222 if (canonized_base_dir
[last_slash
] == '/' &&
223 canonized_base_dir
[last_slash
+ 1] != '\0') {
224 /* canonized_base_dir has some own additional components
225 (i.e. it is not the parent of canonized_dir_name) */
226 for (i
= last_slash
; canonized_base_dir
[i
] != '\0'; i
++) {
227 if (canonized_base_dir
[i
] == '/') {
228 /* go up one level in the relative path */
229 if (ret_val
!= NULL
) ret_val
= mputc(ret_val
, '/');
230 ret_val
= mputstr(ret_val
, "..");
234 if (canonized_dir_name
[last_slash
] == '/' &&
235 canonized_dir_name
[last_slash
+ 1] != '\0') {
236 /* canonized_dir_name has some own additional components
237 (i.e. it is not the parent of canonized_base_dir) */
238 /* append the remaining parts of canonized_dir_name to the result */
239 if (ret_val
!= NULL
) ret_val
= mputc(ret_val
, '/');
240 ret_val
= mputstr(ret_val
, canonized_dir_name
+ last_slash
+ 1);
243 Free(canonized_dir_name
);
244 Free(canonized_base_dir
);