Merge pull request #10 from egerpil/master
[deliverable/titan.core.git] / common / path.c
CommitLineData
970ed795 1///////////////////////////////////////////////////////////////////////////////
3abe9331 2// Copyright (c) 2000-2015 Ericsson Telecom AB
970ed795
EL
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
19expstring_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
47int 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
64enum 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
79expstring_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
100expstring_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
115expstring_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
feade998 132expstring_t get_absolute_dir(const char *dir_name, const char *base_dir, const int with_error)
970ed795
EL
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 }
feade998 145 if (dir_name != NULL && with_error && set_working_dir(dir_name)) {
970ed795
EL
146 /* there was an error: go back to initial_dir */
147 set_working_dir(initial_dir);
148 Free(initial_dir);
149 return NULL;
150 }
feade998 151 if (dir_name != NULL && !with_error && chdir(dir_name)) {
152 //No error sign
153 errno = 0;
154 Free(initial_dir);
155 return NULL;
156 }
970ed795
EL
157 ret_val = get_working_dir();
158 /* restore the working directory */
159 set_working_dir(initial_dir);
160 Free(initial_dir);
161 if (ret_val != NULL &&
162#if defined WIN32 && defined MINGW
163 /* On native Windows the absolute path name shall begin with
164 * a drive letter, colon and backslash */
165 (((ret_val[0] < 'A' || ret_val[0] > 'Z') &&
166 (ret_val[0] < 'a' || ret_val[0] > 'z')) ||
167 ret_val[1] != ':' || ret_val[2] != '\\')
168#else
169 /* On UNIX-like systems the absolute path name shall begin with
170 * a slash */
171 ret_val[0] != '/'
172#endif
173 )
174 path_error("Internal error: `%s' is not a valid absolute pathname.",
175 ret_val);
176 return ret_val;
177}
178
179expstring_t get_relative_dir(const char *dir_name, const char *base_dir)
180{
181 expstring_t ret_val = NULL;
182 /* canonize dir_name and the base directory */
feade998 183 expstring_t canonized_dir_name = get_absolute_dir(dir_name, base_dir, 1);
970ed795 184 expstring_t canonized_base_dir = base_dir != NULL ?
feade998 185 get_absolute_dir(base_dir, NULL, 1) : get_working_dir();
970ed795
EL
186 size_t i, last_slash = 0;
187 if (canonized_dir_name == NULL || canonized_base_dir == NULL) {
188 /* an error occurred */
189 Free(canonized_dir_name);
190 Free(canonized_base_dir);
191 return NULL;
192 }
193 /* skip over the common leading directory part of canonized_dir_name and
194 canonized_base_dir */
195 for (i = 1; ; i++) {
196 char dir_c = canonized_dir_name[i];
197 char base_c = canonized_base_dir[i];
198 if (dir_c == '\0') {
199 /* we must update last_slash if dir_name is a parent of base_dir */
200 if (base_c == '/') last_slash = i;
201 /* we must stop anyway */
202 break;
203 } else if (dir_c == '/') {
204 if (base_c == '/' || base_c == '\0') last_slash = i;
205 if (base_c != '/') break;
206 } else {
207 if (dir_c != base_c) break;
208 }
209 }
210 if (canonized_dir_name[i] == '\0' && canonized_base_dir[i] == '\0') {
211 /* canonized_dir_name and canonized_base_dir are the same */
212 ret_val = mcopystr(".");
213 } else {
214 if (canonized_base_dir[last_slash] == '/' &&
215 canonized_base_dir[last_slash + 1] != '\0') {
216 /* canonized_base_dir has some own additional components
217 (i.e. it is not the parent of canonized_dir_name) */
218 for (i = last_slash; canonized_base_dir[i] != '\0'; i++) {
219 if (canonized_base_dir[i] == '/') {
220 /* go up one level in the relative path */
221 if (ret_val != NULL) ret_val = mputc(ret_val, '/');
222 ret_val = mputstr(ret_val, "..");
223 }
224 }
225 }
226 if (canonized_dir_name[last_slash] == '/' &&
227 canonized_dir_name[last_slash + 1] != '\0') {
228 /* canonized_dir_name has some own additional components
229 (i.e. it is not the parent of canonized_base_dir) */
230 /* append the remaining parts of canonized_dir_name to the result */
231 if (ret_val != NULL) ret_val = mputc(ret_val, '/');
232 ret_val = mputstr(ret_val, canonized_dir_name + last_slash + 1);
233 }
234 }
235 Free(canonized_dir_name);
236 Free(canonized_base_dir);
237 return ret_val;
238}
This page took 0.044499 seconds and 5 git commands to generate.