File: path.c

package info (click to toggle)
eclipse-titan 6.5.0-1
  • links: PTS
  • area: main
  • in suites: buster
  • size: 101,128 kB
  • sloc: cpp: 259,139; ansic: 47,560; yacc: 22,554; makefile: 14,074; sh: 12,630; lex: 9,101; xml: 5,362; java: 4,849; perl: 3,784; awk: 48; php: 32; python: 13
file content (246 lines) | stat: -rw-r--r-- 7,723 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/******************************************************************************
 * Copyright (c) 2000-2018 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
 *
 * Contributors:
 *   Balasko, Jeno
 *   Forstner, Matyas
 *   Raduly, Csaba
 *   Szabo, Bence Janos
 *   Szabo, Janos Zoltan – initial implementation
 *
 ******************************************************************************/
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>

#include "memory.h"
#include "path.h"

/* Initial buffer size for getcwd */
#define BUFSIZE 1024

expstring_t get_working_dir(void)
{
    expstring_t ret_val = NULL;
    char buf[BUFSIZE];
    const char *buf_ptr;
    buf_ptr = getcwd(buf, sizeof(buf));
    if (buf_ptr != NULL) ret_val = mcopystr(buf_ptr);
    else if (errno == ERANGE) {
	/* the initial buffer size is not enough */
	size_t size;
	for (size = 2 * BUFSIZE; ; size *= 2) {
	    char *tmp = (char*)Malloc(size);
	    buf_ptr = getcwd(tmp, size);
	    if (buf_ptr != NULL) ret_val = mcopystr(buf_ptr);
	    Free(tmp);
	    if (buf_ptr != NULL || errno != ERANGE) break;
	}
    }
    if (ret_val == NULL) {
	/* an error occurred */
	path_error("Getting the current working directory failed: %s",
	    strerror(errno));
    }
    /* clear the possible error codes */
    errno = 0;
    return ret_val;
}

int set_working_dir(const char *new_dir)
{
    if (new_dir == NULL) {
	/* invalid argument */
	return 1;
    } else if (chdir(new_dir)) {
	/* an error occurred */
	path_error("Setting the current working directory to `%s' failed: %s",
	    new_dir, strerror(errno));
	errno = 0;
	return 1;
    } else {
	/* everything is OK */
	return 0;
    }
}

enum path_status_t get_path_status(const char *path_name)
{
    struct stat buf;
    if (stat(path_name, &buf)) {
      if (errno != ENOENT) {
	path_error("system call stat() failed on `%s': %s", path_name,
          strerror(errno));
      }
      errno = 0;
      return PS_NONEXISTENT;
    }
    if (S_ISDIR(buf.st_mode)) return PS_DIRECTORY;
    else return PS_FILE;
}

expstring_t get_dir_from_path(const char *path_name)
{
    size_t last_slash_index = (size_t)-1;
    size_t i;
    for (i = 0; path_name[i] != '\0'; i++)
      if (path_name[i] == '/') last_slash_index = i;
    if (last_slash_index == (size_t)-1) {
	/* path_name does not contain any slash */
	return NULL;
    } else if (last_slash_index == 0) {
	/* path_name has the format "/filename": return "/" */
	return mcopystr("/");
    } else {
	/* path_name has the format "<something>/filename":
	   return "<something>" */
	expstring_t ret_val = mcopystr(path_name);
	ret_val = mtruncstr(ret_val, last_slash_index);
	return ret_val;
    }
}

expstring_t get_file_from_path(const char *path_name)
{
    size_t last_slash_index = (size_t)-1;
    size_t i;
    for (i = 0; path_name[i] != '\0'; i++)
      if (path_name[i] == '/') last_slash_index = i;
    if (last_slash_index == (size_t)-1) {
	/* path_name does not contain any slash: return the entire input */
	return mcopystr(path_name);
    } else {
	/* path_name has the format "<something>/filename": return "filename" */
	return mcopystr(path_name + last_slash_index + 1);
    }
}

expstring_t compose_path_name(const char *dir_name,
    const char *file_name)
{
    if (dir_name != NULL && dir_name[0] != '\0') {
	expstring_t ret_val = mcopystr(dir_name);
	if (file_name != NULL && file_name[0] != '\0') {
	    /* neither dir_name nor file_name are empty */
	    size_t dir_name_len = strlen(dir_name);
	    /* do not add the separator slash if dir_name ends with a slash */
	    if (dir_name[dir_name_len - 1] != '/')
		ret_val = mputc(ret_val, '/');
	    ret_val = mputstr(ret_val, file_name);
	}
	return ret_val;
    } else return mcopystr(file_name);
}

expstring_t get_absolute_dir(const char *dir_name, const char *base_dir, const int with_error)
{
    expstring_t ret_val;
    /* save the working directory */
    expstring_t initial_dir = get_working_dir();
    if (base_dir != NULL && (dir_name == NULL || dir_name[0] != '/')) {
	/* go to base_dir first if it is given and dir_name is not an
	   absolute path */
	if (set_working_dir(base_dir)) {
	    Free(initial_dir);
	    return NULL;
	}
    }
    if (dir_name != NULL && with_error && set_working_dir(dir_name)) {
	/* there was an error: go back to initial_dir */
	set_working_dir(initial_dir);
	Free(initial_dir);
	return NULL;
    }
    if (dir_name != NULL && !with_error && chdir(dir_name)) {
        //No error sign
        errno = 0;
	Free(initial_dir);
	return NULL;
    }
    ret_val = get_working_dir();
    /* restore the working directory */
    set_working_dir(initial_dir);
    Free(initial_dir);
    if (ret_val != NULL &&
#if defined WIN32 && defined MINGW
	/* On native Windows the absolute path name shall begin with
	 * a drive letter, colon and backslash */
	(((ret_val[0] < 'A' || ret_val[0] > 'Z') &&
	  (ret_val[0] < 'a' || ret_val[0] > 'z')) ||
	 ret_val[1] != ':' || ret_val[2] != '\\')
#else
	/* On UNIX-like systems the absolute path name shall begin with
	 * a slash */
	ret_val[0] != '/'
#endif
	)
	path_error("Internal error: `%s' is not a valid absolute pathname.",
	    ret_val);
    return ret_val;
}

expstring_t get_relative_dir(const char *dir_name, const char *base_dir)
{
    expstring_t ret_val = NULL;
    /* canonize dir_name and the base directory */
    expstring_t canonized_dir_name = get_absolute_dir(dir_name, base_dir, 1);
    expstring_t canonized_base_dir = base_dir != NULL ?
	get_absolute_dir(base_dir, NULL, 1) : get_working_dir();
    size_t i, last_slash = 0;
    if (canonized_dir_name == NULL || canonized_base_dir == NULL) {
	/* an error occurred */
	Free(canonized_dir_name);
	Free(canonized_base_dir);
	return NULL;
    }
    /* skip over the common leading directory part of canonized_dir_name and
       canonized_base_dir */
    for (i = 1; ; i++) {
	char dir_c = canonized_dir_name[i];
	char base_c = canonized_base_dir[i];
	if (dir_c == '\0') {
	    /* we must update last_slash if dir_name is a parent of base_dir */
	    if (base_c == '/') last_slash = i;
	    /* we must stop anyway */
	    break;
	} else if (dir_c == '/') {
	    if (base_c == '/' || base_c == '\0') last_slash = i;
	    if (base_c != '/') break;
	} else {
	    if (dir_c != base_c) break;
	}
    }
    if (canonized_dir_name[i] == '\0' && canonized_base_dir[i] == '\0') {
	/* canonized_dir_name and canonized_base_dir are the same */
	ret_val = mcopystr(".");
    } else {
	if (canonized_base_dir[last_slash] == '/' &&
	    canonized_base_dir[last_slash + 1] != '\0') {
	    /* canonized_base_dir has some own additional components
	       (i.e. it is not the parent of canonized_dir_name) */
	    for (i = last_slash; canonized_base_dir[i] != '\0'; i++) {
		if (canonized_base_dir[i] == '/') {
		    /* go up one level in the relative path */
		    if (ret_val != NULL) ret_val = mputc(ret_val, '/');
		    ret_val = mputstr(ret_val, "..");
		}
	    }
	}
	if (canonized_dir_name[last_slash] == '/' &&
	    canonized_dir_name[last_slash + 1] != '\0') {
	    /* canonized_dir_name has some own additional components
	       (i.e. it is not the parent of canonized_base_dir) */
	    /* append the remaining parts of canonized_dir_name to the result */
	    if (ret_val != NULL) ret_val = mputc(ret_val, '/');
	    ret_val = mputstr(ret_val, canonized_dir_name + last_slash + 1);
	}
    }
    Free(canonized_dir_name);
    Free(canonized_base_dir);
    return ret_val;
}