1 //========================================================================
5 // Miscellaneous file and directory name manipulation.
7 // Copyright 1996 Derek B. Noonburg
9 //========================================================================
14 # include <kpathsea/win32lib.h>
18 # include <sys/stat.h>
19 # elif !defined(ACORN)
20 # include <sys/types.h>
21 # include <sys/stat.h>
26 # if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
29 # if defined(VMS) && (__DECCXX_VER < 50200000)
37 // Some systems don't define this, so just make it something reasonably
43 //------------------------------------------------------------------------
45 GString *getHomeDir() {
47 //---------- VMS ----------
48 return new GString("SYS$LOGIN:");
50 #elif defined(__EMX__) || defined(WIN32)
51 //---------- OS/2+EMX and Win32 ----------
55 if ((s = getenv("HOME")))
58 ret = new GString(".");
62 //---------- RISCOS ----------
63 return new GString("@");
66 //---------- MacOS ----------
67 return new GString(":");
70 //---------- Unix ----------
75 if ((s = getenv("HOME"))) {
78 if ((s = getenv("USER")))
81 pw = getpwuid(getuid());
83 ret = new GString(pw->pw_dir);
85 ret = new GString(".");
91 GString *getCurrentDir() {
95 if (_getcwd2(buf, sizeof(buf)))
97 if (GetCurrentDirectory(sizeof(buf), buf))
101 if (strcpy(buf, ":"))
103 if (getcwd(buf, sizeof(buf)))
105 return new GString(buf);
106 return new GString();
109 GString *appendToPath(GString *path, char *fileName) {
111 //---------- VMS ----------
112 //~ this should handle everything necessary for file
113 //~ requesters, but it's certainly not complete
117 p0 = path->getCString();
118 p1 = p0 + path->getLength() - 1;
119 if (!strcmp(fileName, "-")) {
121 for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
124 path->del(p2 - p0, p1 - p2);
125 } else if (*p1 == ':') {
131 } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
133 path->insert(p1 - p0, '.');
134 path->insert(p1 - p0 + 1, fileName, q1 - fileName);
135 } else if (*p1 == ':') {
138 path->append(fileName, q1 - fileName);
141 path->append(fileName, q1 - fileName);
144 if (*p1 != ']' && *p1 != ':')
146 path->append(fileName);
151 //---------- Win32 ----------
156 tmp = new GString(path);
158 tmp->append(fileName);
159 GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
166 //---------- RISCOS ----------
171 i = path->getLength();
172 path->append(fileName);
173 for (p = path->getCString() + i; *p; ++p) {
176 } else if (*p == '.') {
183 //---------- MacOS ----------
188 i = path->getLength();
189 path->append(fileName);
190 for (p = path->getCString() + i; *p; ++p) {
193 } else if (*p == '.') {
199 #elif defined(__EMX__)
200 //---------- OS/2+EMX ----------
203 // appending "." does nothing
204 if (!strcmp(fileName, "."))
207 // appending ".." goes up one directory
208 if (!strcmp(fileName, "..")) {
209 for (i = path->getLength() - 2; i >= 0; --i) {
210 if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
211 path->getChar(i) == ':')
215 if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
216 path->del(1, path->getLength() - 1);
217 } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
218 path->del(2, path->getLength() - 2);
224 if (path->getChar(i-1) == ':')
226 path->del(i, path->getLength() - i);
231 // otherwise, append "/" and new path component
232 if (path->getLength() > 0 &&
233 path->getChar(path->getLength() - 1) != '/' &&
234 path->getChar(path->getLength() - 1) != '\\')
236 path->append(fileName);
240 //---------- Unix ----------
243 // appending "." does nothing
244 if (!strcmp(fileName, "."))
247 // appending ".." goes up one directory
248 if (!strcmp(fileName, "..")) {
249 for (i = path->getLength() - 2; i >= 0; --i) {
250 if (path->getChar(i) == '/')
254 if (path->getChar(0) == '/') {
255 path->del(1, path->getLength() - 1);
261 path->del(i, path->getLength() - i);
266 // otherwise, append "/" and new path component
267 if (path->getLength() > 0 &&
268 path->getChar(path->getLength() - 1) != '/')
270 path->append(fileName);
275 GString *grabPath(char *fileName) {
277 //---------- VMS ----------
280 if ((p = strrchr(fileName, ']')))
281 return new GString(fileName, p + 1 - fileName);
282 if ((p = strrchr(fileName, ':')))
283 return new GString(fileName, p + 1 - fileName);
284 return new GString();
286 #elif defined(__EMX__) || defined(WIN32)
287 //---------- OS/2+EMX and Win32 ----------
290 if ((p = strrchr(fileName, '/')))
291 return new GString(fileName, p - fileName);
292 if ((p = strrchr(fileName, '\\')))
293 return new GString(fileName, p - fileName);
294 if ((p = strrchr(fileName, ':')))
295 return new GString(fileName, p + 1 - fileName);
296 return new GString();
299 //---------- RISCOS ----------
302 if ((p = strrchr(fileName, '.')))
303 return new GString(fileName, p - fileName);
304 return new GString();
307 //---------- MacOS ----------
310 if ((p = strrchr(fileName, ':')))
311 return new GString(fileName, p - fileName);
312 return new GString();
315 //---------- Unix ----------
318 if ((p = strrchr(fileName, '/')))
319 return new GString(fileName, p - fileName);
320 return new GString();
324 GBool isAbsolutePath(char *path) {
326 //---------- VMS ----------
327 return strchr(path, ':') ||
328 (path[0] == '[' && path[1] != '.' && path[1] != '-');
330 #elif defined(__EMX__) || defined(WIN32)
331 //---------- OS/2+EMX and Win32 ----------
332 return path[0] == '/' || path[0] == '\\' || path[1] == ':';
335 //---------- RISCOS ----------
336 return path[0] == '$';
339 //---------- MacOS ----------
340 return path[0] != ':';
343 //---------- Unix ----------
344 return path[0] == '/';
348 GString *makePathAbsolute(GString *path) {
350 //---------- VMS ----------
351 char buf[PATH_MAX+1];
353 if (!isAbsolutePath(path->getCString())) {
354 if (getcwd(buf, sizeof(buf))) {
355 path->insert(0, buf);
361 //---------- Win32 ----------
366 if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
375 //---------- RISCOS ----------
376 path->insert(0, '@');
380 //---------- MacOS ----------
385 //---------- Unix and OS/2+EMX ----------
387 char buf[PATH_MAX+1];
392 if (path->getChar(0) == '~') {
393 if (path->getChar(1) == '/' ||
395 path->getChar(1) == '\\' ||
397 path->getLength() == 1) {
403 p1 = path->getCString() + 1;
405 for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
407 for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
409 if ((n = p2 - p1) > PATH_MAX)
413 if ((pw = getpwnam(buf))) {
414 path->del(0, p2 - p1 + 1);
415 path->insert(0, pw->pw_dir);
418 } else if (!isAbsolutePath(path->getCString())) {
419 if (getcwd(buf, sizeof(buf))) {
421 path->insert(0, '/');
423 path->insert(0, buf);
430 time_t getModTime(char *fileName) {
432 //~ should implement this, but it's (currently) only used in xpdf
437 if (stat(fileName, &statBuf)) {
440 return statBuf.st_mtime;
444 GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
445 #if defined(VMS) || defined(__EMX__) || defined(WIN32) || defined(ACORN) || defined(MACOS)
446 //---------- non-Unix ----------
449 // There is a security hole here: an attacker can create a symlink
450 // with this file name after the tmpnam call and before the fopen
451 // call. I will happily accept fixes to this function for non-Unix
453 if (!(s = tmpnam(NULL))) {
456 *name = new GString(s);
458 (*name)->append(ext);
460 if (!(*f = fopen((*name)->getCString(), mode))) {
466 //---------- Unix ----------
471 if (!(s = tmpnam(NULL))) {
474 *name = new GString(s);
475 s = (*name)->getCString();
476 if ((p = strrchr(s, '.'))) {
477 (*name)->del(p - s, (*name)->getLength() - (p - s));
479 (*name)->append(ext);
480 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
483 if ((s = getenv("TMPDIR"))) {
484 *name = new GString(s);
486 *name = new GString("/tmp");
488 (*name)->append("/XXXXXX");
489 fd = mkstemp((*name)->getCString());
490 #else // HAVE_MKSTEMP
491 if (!(s = tmpnam(NULL))) {
494 *name = new GString(s);
495 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
496 #endif // HAVE_MKSTEMP
498 if (fd < 0 || !(*f = fdopen(fd, mode))) {
506 //------------------------------------------------------------------------
507 // GDir and GDirEntry
508 //------------------------------------------------------------------------
510 GDirEntry::GDirEntry(char *dirPath, char *name1, GBool doStat) {
522 name = new GString(name1);
526 if (!strcmp(name1, "-") ||
527 ((p = strrchr(name1, '.')) && !strncmp(p, ".DIR;", 5)))
531 s = new GString(dirPath);
532 appendToPath(s, name1);
534 fa = GetFileAttributes(s->getCString());
535 dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
537 if (stat(s->getCString(), &st) == 0)
538 dir = S_ISDIR(st.st_mode);
545 GDirEntry::~GDirEntry() {
549 GDir::GDir(char *name, GBool doStat1) {
550 path = new GString(name);
557 hnd = FindFirstFile(tmp->getCString(), &ffd);
564 needParent = strchr(name, '[') != NULL;
584 GDirEntry *GDir::getNextEntry() {
590 e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
591 if (hnd && !FindNextFile(hnd, &ffd)) {
601 e = new GDirEntry(path->getCString(), "-", doStat);
608 if (ent && !strcmp(ent->d_name, "."))
612 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
618 void GDir::rewind() {
626 hnd = FindFirstFile(tmp->getCString(), &ffd);
633 needParent = strchr(path->getCString(), '[') != NULL;