Titan Core Initial Contribution
[deliverable/titan.core.git] / common / path.c
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 ///////////////////////////////////////////////////////////////////////////////
8 #include <string.h>
9 #include <errno.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12
13 #include "memory.h"
14 #include "path.h"
15
16 /* Initial buffer size for getcwd */
17 #define BUFSIZE 1024
18
19 expstring_t get_working_dir(void)
20 {
21 expstring_t ret_val = NULL;
22 char buf[BUFSIZE];
23 const char *buf_ptr;
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 */
28 size_t size;
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);
33 Free(tmp);
34 if (buf_ptr != NULL || errno != ERANGE) break;
35 }
36 }
37 if (ret_val == NULL) {
38 /* an error occurred */
39 path_error("Getting the current working directory failed: %s",
40 strerror(errno));
41 }
42 /* clear the possible error codes */
43 errno = 0;
44 return ret_val;
45 }
46
47 int set_working_dir(const char *new_dir)
48 {
49 if (new_dir == NULL) {
50 /* invalid argument */
51 return 1;
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));
56 errno = 0;
57 return 1;
58 } else {
59 /* everything is OK */
60 return 0;
61 }
62 }
63
64 enum path_status_t get_path_status(const char *path_name)
65 {
66 struct stat buf;
67 if (stat(path_name, &buf)) {
68 if (errno != ENOENT) {
69 path_error("system call stat() failed on `%s': %s", path_name,
70 strerror(errno));
71 }
72 errno = 0;
73 return PS_NONEXISTENT;
74 }
75 if (S_ISDIR(buf.st_mode)) return PS_DIRECTORY;
76 else return PS_FILE;
77 }
78
79 expstring_t get_dir_from_path(const char *path_name)
80 {
81 size_t last_slash_index = (size_t)-1;
82 size_t i;
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 */
87 return NULL;
88 } else if (last_slash_index == 0) {
89 /* path_name has the format "/filename": return "/" */
90 return mcopystr("/");
91 } else {
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);
96 return ret_val;
97 }
98 }
99
100 expstring_t get_file_from_path(const char *path_name)
101 {
102 size_t last_slash_index = (size_t)-1;
103 size_t i;
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);
109 } else {
110 /* path_name has the format "<something>/filename": return "filename" */
111 return mcopystr(path_name + last_slash_index + 1);
112 }
113 }
114
115 expstring_t compose_path_name(const char *dir_name,
116 const char *file_name)
117 {
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);
127 }
128 return ret_val;
129 } else return mcopystr(file_name);
130 }
131
132 expstring_t get_absolute_dir(const char *dir_name, const char *base_dir)
133 {
134 expstring_t ret_val;
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
139 absolute path */
140 if (set_working_dir(base_dir)) {
141 Free(initial_dir);
142 return NULL;
143 }
144 }
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);
148 Free(initial_dir);
149 return NULL;
150 }
151 ret_val = get_working_dir();
152 /* restore the working directory */
153 set_working_dir(initial_dir);
154 Free(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] != '\\')
162 #else
163 /* On UNIX-like systems the absolute path name shall begin with
164 * a slash */
165 ret_val[0] != '/'
166 #endif
167 )
168 path_error("Internal error: `%s' is not a valid absolute pathname.",
169 ret_val);
170 return ret_val;
171 }
172
173 expstring_t get_relative_dir(const char *dir_name, const char *base_dir)
174 {
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);
185 return NULL;
186 }
187 /* skip over the common leading directory part of canonized_dir_name and
188 canonized_base_dir */
189 for (i = 1; ; i++) {
190 char dir_c = canonized_dir_name[i];
191 char base_c = canonized_base_dir[i];
192 if (dir_c == '\0') {
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 */
196 break;
197 } else if (dir_c == '/') {
198 if (base_c == '/' || base_c == '\0') last_slash = i;
199 if (base_c != '/') break;
200 } else {
201 if (dir_c != base_c) break;
202 }
203 }
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(".");
207 } else {
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, "..");
217 }
218 }
219 }
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);
227 }
228 }
229 Free(canonized_dir_name);
230 Free(canonized_base_dir);
231 return ret_val;
232 }
This page took 0.037098 seconds and 5 git commands to generate.