Update README.md
[deliverable/titan.core.git] / common / path.c
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
7 *
8 * Contributors:
9 * Balasko, Jeno
10 * Forstner, Matyas
11 * Raduly, Csaba
12 * Szabo, Bence Janos
13 * Szabo, Janos Zoltan – initial implementation
14 *
15 ******************************************************************************/
16 #include <string.h>
17 #include <errno.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20
21 #include "memory.h"
22 #include "path.h"
23
24 /* Initial buffer size for getcwd */
25 #define BUFSIZE 1024
26
27 expstring_t get_working_dir(void)
28 {
29 expstring_t ret_val = NULL;
30 char buf[BUFSIZE];
31 const char *buf_ptr;
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 */
36 size_t size;
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);
41 Free(tmp);
42 if (buf_ptr != NULL || errno != ERANGE) break;
43 }
44 }
45 if (ret_val == NULL) {
46 /* an error occurred */
47 path_error("Getting the current working directory failed: %s",
48 strerror(errno));
49 }
50 /* clear the possible error codes */
51 errno = 0;
52 return ret_val;
53 }
54
55 int set_working_dir(const char *new_dir)
56 {
57 if (new_dir == NULL) {
58 /* invalid argument */
59 return 1;
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));
64 errno = 0;
65 return 1;
66 } else {
67 /* everything is OK */
68 return 0;
69 }
70 }
71
72 enum path_status_t get_path_status(const char *path_name)
73 {
74 struct stat buf;
75 if (stat(path_name, &buf)) {
76 if (errno != ENOENT) {
77 path_error("system call stat() failed on `%s': %s", path_name,
78 strerror(errno));
79 }
80 errno = 0;
81 return PS_NONEXISTENT;
82 }
83 if (S_ISDIR(buf.st_mode)) return PS_DIRECTORY;
84 else return PS_FILE;
85 }
86
87 expstring_t get_dir_from_path(const char *path_name)
88 {
89 size_t last_slash_index = (size_t)-1;
90 size_t i;
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 */
95 return NULL;
96 } else if (last_slash_index == 0) {
97 /* path_name has the format "/filename": return "/" */
98 return mcopystr("/");
99 } else {
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);
104 return ret_val;
105 }
106 }
107
108 expstring_t get_file_from_path(const char *path_name)
109 {
110 size_t last_slash_index = (size_t)-1;
111 size_t i;
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);
117 } else {
118 /* path_name has the format "<something>/filename": return "filename" */
119 return mcopystr(path_name + last_slash_index + 1);
120 }
121 }
122
123 expstring_t compose_path_name(const char *dir_name,
124 const char *file_name)
125 {
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);
135 }
136 return ret_val;
137 } else return mcopystr(file_name);
138 }
139
140 expstring_t get_absolute_dir(const char *dir_name, const char *base_dir, const int with_error)
141 {
142 expstring_t ret_val;
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
147 absolute path */
148 if (set_working_dir(base_dir)) {
149 Free(initial_dir);
150 return NULL;
151 }
152 }
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);
156 Free(initial_dir);
157 return NULL;
158 }
159 if (dir_name != NULL && !with_error && chdir(dir_name)) {
160 //No error sign
161 errno = 0;
162 Free(initial_dir);
163 return NULL;
164 }
165 ret_val = get_working_dir();
166 /* restore the working directory */
167 set_working_dir(initial_dir);
168 Free(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] != '\\')
176 #else
177 /* On UNIX-like systems the absolute path name shall begin with
178 * a slash */
179 ret_val[0] != '/'
180 #endif
181 )
182 path_error("Internal error: `%s' is not a valid absolute pathname.",
183 ret_val);
184 return ret_val;
185 }
186
187 expstring_t get_relative_dir(const char *dir_name, const char *base_dir)
188 {
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);
199 return NULL;
200 }
201 /* skip over the common leading directory part of canonized_dir_name and
202 canonized_base_dir */
203 for (i = 1; ; i++) {
204 char dir_c = canonized_dir_name[i];
205 char base_c = canonized_base_dir[i];
206 if (dir_c == '\0') {
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 */
210 break;
211 } else if (dir_c == '/') {
212 if (base_c == '/' || base_c == '\0') last_slash = i;
213 if (base_c != '/') break;
214 } else {
215 if (dir_c != base_c) break;
216 }
217 }
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(".");
221 } else {
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, "..");
231 }
232 }
233 }
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);
241 }
242 }
243 Free(canonized_dir_name);
244 Free(canonized_base_dir);
245 return ret_val;
246 }
This page took 0.035709 seconds and 5 git commands to generate.