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 /* We need to check if driver is cdrom because those one use \ as separator */
75 if (devname_len == 5 && (memcmp(d, "cdrom", 5) == 0))
76 {
77 *usePOSIXSeparator = SeparatorTypeWindows;
78 }
79 /* We need to check if drive is rom or hdd because those one don't have separator */
80 else if (devname_len == 3 && ((memcmp(d, "rom", 3) == 0) || (memcmp(d, "hdd", 3) == 0)))
81 {
82 *usePOSIXSeparator = SeparatorTypeNone;
83 }
84 else
85 {
86 *usePOSIXSeparator = SeparatorTypePOSIX;
87 }
88
89 /* Return the length of the whole device name portion, including:
90 * - leading spaces
91 * - device name
92 * - device index
93 * - colon
94 */
95 return (tail - dev) + 1;
96}
97#else
98int __get_drive(const char *dev, enum SeparatorType *usePOSIXSeparator);
99#endif
100
101#ifdef F_getcwd
102char *getcwd(char *buf, size_t size)
103{
104 if(!buf) {
105 errno = EINVAL;
106 return NULL;
107 }
108
109 if(__cwd_len >= size) {
110 errno = ERANGE;
111 return NULL;
112 }
113
114 memcpy(buf, __cwd, __cwd_len);
115 buf[__cwd_len] = '\x00';
116 return buf;
117}
118#endif
119
120#ifdef F___path_absolute
121/* Normalize a pathname (without leading "drive:") by removing
122 . and .. components, duplicated /, etc. */
123static int __path_normalize(char *out, int len, int posixSeparator)
124{
125 int i, j;
126 int first, next;
127 char separator = posixSeparator ? '/' : '\\';
128 size_t out_len = strnlen(out, len);
129
130 out_len += 2;
131 if (out_len >= len) return -10;
132
133 /* First append "/" to make the rest easier */
134 out[out_len - 1] = separator;
135 out[out_len] = 0;
136
137 // Convert separators to the specified one
138 for (size_t i = 0; i < out_len; i++) {
139 if (out[i] == '/' || out[i] == '\\') {
140 out[i] = separator;
141 }
142 }
143
144 /* Convert "//" to "/" */
145 for(i = 0; (i < out_len) && out[i+1]; i++) {
146 if(out[i] == separator && out[i+1] == separator) {
147 for(j=i+1; out[j]; j++)
148 out[j] = out[j+1];
149 i--;
150 }
151 }
152
153 /* Convert "/./" to "/" */
154 for(i = 0; (i < out_len) && out[i] && out[i+1] && out[i+2]; i++) {
155 if(out[i] == separator && out[i+1] == '.' && out[i+2] == separator) {
156 for(j = i+1; out[j]; j++)
157 out[j] = out[j+2];
158 i--;
159 }
160 }
161
162 /* Convert "/asdf/../" to "/" until we can't anymore. Also
163 * convert leading "/../" to "/" */
164 first = next = 0;
165 while((first < out_len) && (next < out_len)) {
166 /* If a "../" follows, remove it and the parent */
167 if(out[next+1] && out[next+1] == '.' &&
168 out[next+2] && out[next+2] == '.' &&
169 out[next+3] && out[next+3] == separator) {
170 for(j=0; out[first+j+1]; j++)
171 out[first+j+1] = out[next+j+4];
172 first = next = 0;
173 continue;
174 }
175
176 /* Find next slash */
177 first = next;
178 for(next= first+1; out[next] && out[next] != separator; next++)
179 continue;
180 if(!out[next]) break;
181 }
182
183 /* Remove trailing "/" just if it's not the root */
184 for(i = 1; (i < out_len) && out[i]; i++)
185 continue;
186 if(i > 1 && out[i-1] == separator)
187 out[i-1] = 0;
188
189 return 0;
190}
191
192/* Convert relative path to absolute path. */
193int __path_absolute(const char *in, char *out, int len)
194{
195 int dr;
196 enum SeparatorType separatorType;
197 size_t in_len;
198
199 in_len = strlen(in);
200 /* See what the relative URL starts with */
201 dr = __get_drive(in, &separatorType);
202 char separator = separatorType == SeparatorTypePOSIX ? '/' : '\\';
203
204 if(dr > 0 && (separatorType == SeparatorTypeNone || in[dr] == separator)) {
205 /* It starts with "drive:" and has no separator or "drive:/", so it's already absolute */
206 if (in_len >= len) return -1;
207 strncpy(out, in, len);
208 } else if(dr > 0 && in[dr - 1] == ':') {
209 /* It starts with "drive:", so it's already absoulte, however it misses the "/" after unit */
210 if (in_len + 1 >= len) return -2;
211 strncpy(out, in, dr);
212 out[dr] = separator;
213 strncpy(out + dr + 1, in + dr, len - dr - 1);
214 } else if(in[0] == '\\' || in[0] == '/') {
215 /* It's absolute, but missing the drive, so use cwd's drive */
216 if(__cwd_len + in_len >= len) return -3;
217 memcpy(out, __cwd, __cwd_len);
218 out[__cwd_len] = '\x00';
219 dr = __get_drive(out, &separatorType);
220 if(dr < 0) dr = 0;
221 out[dr] = 0;
222 strncat(out, in, len);
223 } else {
224 /* It's not absolute, so append it to the current cwd */
225 if(__cwd_len + 1 + in_len >= len) return -5;
226 memcpy(out, __cwd, __cwd_len);
227 out[__cwd_len] = separator;
228 out[__cwd_len + 1] = '\x00';
229 strncat(out, in, len);
230 }
231
232 /* Now normalize the pathname portion */
233 dr = __get_drive(out, &separatorType);
234 if(dr < 0) dr = 0;
235 return __path_normalize(out + dr, len - dr, separatorType == SeparatorTypePOSIX);
236}
237#endif
238
239#ifdef F___init_cwd
240/* Set the current working directory (CWD) to the path where the module was launched. */
241void __init_cwd(int argc, char ** argv)
242{
243 if (argc == 0) {
244 chdir("host:");
245 return;
246 }
247
248 char * p, * s = NULL;
249 // let's find the last slash, or at worst, the :
250 for (p = argv[0]; *p; p++) {
251 if ((*p == '/') || (*p == '\\') || (*p == ':')) {
252 s = p;
253 }
254 }
255 if (s == NULL)
256 {
257 chdir("host:");
258 return;
259 }
260 char backup = *(++s);
261 *s = 0;
262 chdir(argv[0]);
263 *s = backup;
264}
265#endif
#define EINVAL
Definition errno.h:63
#define ERANGE
Definition errno.h:87