PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
cwd.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
11#include <stdio.h>
12#include <unistd.h>
13#include <string.h>
14#include <ctype.h>
15#include <sys/param.h>
16#include <dirent.h>
17#include <errno.h>
18
19#ifdef F___cwd
20/* the present working directory variable. */
21char __cwd[MAXNAMLEN + 1] = { 0 };
22#else
23extern char __cwd[MAXNAMLEN + 1];
24#endif
25
26#ifdef F___cwd_len
27/* the length of the present working directory variable. */
28size_t __cwd_len = 0;
29#else
30extern size_t __cwd_len;
31#endif
32
33#define defaultCWD "host:"
34
35enum SeparatorType {
36 SeparatorTypeNone,
37 SeparatorTypePOSIX,
38 SeparatorTypeWindows
39};
40
41#define isnum(c) ((c) >= '0' && (c) <= '9')
42
43#ifdef F___get_drive
44/* Return the number of bytes taken up by the "drive:" prefix,
45 or -1 if it's not found */
46int __get_drive(const char *dev, enum SeparatorType *usePOSIXSeparator)
47{
48 const char *tail;
49 const char *d;
50 int devname_len;
51
52 /* Skip leading spaces */
53 d = dev;
54 while (*d == ' ')
55 {
56 d += 1;
57 }
58
59 /* Get colon position */
60 tail = strchr(d, ':');
61 if (tail == NULL)
62 {
63 return -1;
64 }
65
66 devname_len = (int)(tail - d);
67
68 /* Reduce length to not include index */
69 while (isnum(d[devname_len - 1]))
70 {
71 devname_len -= 1;
72 }
73
74 *usePOSIXSeparator = SeparatorTypePOSIX;
75 switch (devname_len)
76 {
77 case 3:
78 /* These drivers don't have separator */
79 if ((memcmp(d, "rom", devname_len) == 0) || (memcmp(d, "hdd", devname_len) == 0))
80 *usePOSIXSeparator = SeparatorTypeNone;
81 break;
82 case 5:
83 /* These drivers use \ as separator */
84 if ((memcmp(d, "cdrom", devname_len) == 0))
85 *usePOSIXSeparator = SeparatorTypeWindows;
86 break;
87 case 6:
88 /* These drivers don't have separator */
89 if ((memcmp(d, "usbkbd", devname_len) == 0))
90 *usePOSIXSeparator = SeparatorTypeNone;
91 break;
92 default:
93 break;
94 }
95
96 /* Return the length of the whole device name portion, including:
97 * - leading spaces
98 * - device name
99 * - device index
100 * - colon
101 */
102 return (tail - dev) + 1;
103}
104#else
105int __get_drive(const char *dev, enum SeparatorType *usePOSIXSeparator);
106#endif
107
108#ifdef F_getcwd
109char *getcwd(char *buf, size_t size)
110{
111 if(!buf) {
112 errno = EINVAL;
113 return NULL;
114 }
115
116 if(__cwd_len >= size) {
117 errno = ERANGE;
118 return NULL;
119 }
120
121 memcpy(buf, __cwd, __cwd_len);
122 buf[__cwd_len] = '\x00';
123 return buf;
124}
125#endif
126
127#ifdef F___path_absolute
128/* Normalize a pathname (without leading "drive:") by removing
129 . and .. components, duplicated /, etc. */
130static int __path_normalize(char *out, int len, int posixSeparator)
131{
132 int i, j;
133 int first, next;
134 char separator = posixSeparator ? '/' : '\\';
135 size_t out_len = strnlen(out, len);
136
137 out_len += 2;
138 if (out_len >= len) return -10;
139
140 /* First append "/" to make the rest easier */
141 out[out_len - 1] = separator;
142 out[out_len] = 0;
143
144 // Convert separators to the specified one
145 for (size_t i = 0; i < out_len; i++) {
146 if (out[i] == '/' || out[i] == '\\') {
147 out[i] = separator;
148 }
149 }
150
151 /* Convert "//" to "/" */
152 for(i = 0; (i < out_len) && out[i+1]; i++) {
153 if(out[i] == separator && out[i+1] == separator) {
154 for(j=i+1; out[j]; j++)
155 out[j] = out[j+1];
156 i--;
157 }
158 }
159
160 /* Convert "/./" to "/" */
161 for(i = 0; (i < out_len) && out[i] && out[i+1] && out[i+2]; i++) {
162 if(out[i] == separator && out[i+1] == '.' && out[i+2] == separator) {
163 for(j = i+1; out[j]; j++)
164 out[j] = out[j+2];
165 i--;
166 }
167 }
168
169 /* Convert "/asdf/../" to "/" until we can't anymore. Also
170 * convert leading "/../" to "/" */
171 first = next = 0;
172 while((first < out_len) && (next < out_len)) {
173 /* If a "../" follows, remove it and the parent */
174 if(out[next+1] && out[next+1] == '.' &&
175 out[next+2] && out[next+2] == '.' &&
176 out[next+3] && out[next+3] == separator) {
177 for(j=0; out[first+j+1]; j++)
178 out[first+j+1] = out[next+j+4];
179 first = next = 0;
180 continue;
181 }
182
183 /* Find next slash */
184 first = next;
185 for(next= first+1; out[next] && out[next] != separator; next++)
186 continue;
187 if(!out[next]) break;
188 }
189
190 /* Remove trailing "/" just if it's not the root */
191 for(i = 1; (i < out_len) && out[i]; i++)
192 continue;
193 if(i > 1 && out[i-1] == separator)
194 out[i-1] = 0;
195
196 return 0;
197}
198
199/* Convert relative path to absolute path. */
200int __path_absolute(const char *in, char *out, int len)
201{
202 int dr;
203 enum SeparatorType separatorType;
204 size_t in_len;
205
206 in_len = strlen(in);
207 /* See what the relative URL starts with */
208 dr = __get_drive(in, &separatorType);
209 char separator = separatorType == SeparatorTypePOSIX ? '/' : '\\';
210
211 if(dr > 0 && (separatorType == SeparatorTypeNone || in[dr] == separator)) {
212 /* It starts with "drive:" and has no separator or "drive:/", so it's already absolute */
213 if (in_len >= len) return -1;
214 strncpy(out, in, len);
215 } else if(dr > 0 && in[dr - 1] == ':') {
216 /* It starts with "drive:", so it's already absoulte, however it misses the "/" after unit */
217 if (in_len + 1 >= len) return -2;
218 strncpy(out, in, dr);
219 out[dr] = separator;
220 strncpy(out + dr + 1, in + dr, len - dr - 1);
221 } else if(in[0] == '\\' || in[0] == '/') {
222 /* It's absolute, but missing the drive, so use cwd's drive */
223 if(__cwd_len + in_len >= len) return -3;
224 memcpy(out, __cwd, __cwd_len);
225 out[__cwd_len] = '\x00';
226 dr = __get_drive(out, &separatorType);
227 if(dr < 0) dr = 0;
228 out[dr] = 0;
229 strncat(out, in, len);
230 } else {
231 /* It's not absolute, so append it to the current cwd */
232 if(__cwd_len + 1 + in_len >= len) return -5;
233 memcpy(out, __cwd, __cwd_len);
234 out[__cwd_len] = separator;
235 out[__cwd_len + 1] = '\x00';
236 strncat(out, in, len);
237 }
238
239 /* Now normalize the pathname portion */
240 dr = __get_drive(out, &separatorType);
241 if(dr < 0) dr = 0;
242 return __path_normalize(out + dr, len - dr, separatorType == SeparatorTypePOSIX);
243}
244#endif
245
246#ifdef F___init_cwd
247/* Set the current working directory (CWD) to the path where the module was launched. */
248void __init_cwd(int argc, char ** argv)
249{
250 if (argc == 0) {
251 chdir("host:");
252 return;
253 }
254
255 char * p, * s = NULL;
256 // let's find the last slash, or at worst, the :
257 for (p = argv[0]; *p; p++) {
258 if ((*p == '/') || (*p == '\\') || (*p == ':')) {
259 s = p;
260 }
261 }
262 if (s == NULL)
263 {
264 chdir("host:");
265 return;
266 }
267 char backup = *(++s);
268 *s = 0;
269 chdir(argv[0]);
270 *s = backup;
271}
272#endif
#define EINVAL
Definition errno.h:63
#define ERANGE
Definition errno.h:87