1 //========================================================================
5 // Miscellaneous file and directory name manipulation.
7 // Copyright 1996 Derek B. Noonburg
9 //========================================================================
11 #include "../../config.h"
15 # include <kpathsea/win32lib.h>
20 # include <sys/stat.h>
21 # elif !defined(ACORN)
22 # include <sys/types.h>
23 # include <sys/stat.h>
28 # if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
31 # if defined(VMS) && (__DECCXX_VER < 50200000)
38 // Some systems don't define this, so just make it something reasonably
44 //------------------------------------------------------------------------
46 GString *getHomeDir() {
48 //---------- VMS ----------
49 return new GString("SYS$LOGIN:");
51 #elif defined(__EMX__) || defined(WIN32)
52 //---------- OS/2+EMX and Win32 ----------
56 if ((s = getenv("HOME")))
59 ret = new GString(".");
63 //---------- RISCOS ----------
64 return new GString("@");
67 //---------- MacOS ----------
68 return new GString(":");
71 //---------- Unix ----------
76 if ((s = getenv("HOME"))) {
79 if ((s = getenv("USER")))
82 pw = getpwuid(getuid());
84 ret = new GString(pw->pw_dir);
86 ret = new GString(".");
92 GString *getCurrentDir() {
96 if (_getcwd2(buf, sizeof(buf)))
98 if (GetCurrentDirectory(sizeof(buf), buf))
100 if (strcpy(buf, "@"))
102 if (strcpy(buf, ":"))
104 if (getcwd(buf, sizeof(buf)))
106 return new GString(buf);
107 return new GString();
110 GString *appendToPath(GString *path, char *fileName) {
112 //---------- VMS ----------
113 //~ this should handle everything necessary for file
114 //~ requesters, but it's certainly not complete
118 p0 = path->getCString();
119 p1 = p0 + path->getLength() - 1;
120 if (!strcmp(fileName, "-")) {
122 for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
125 path->del(p2 - p0, p1 - p2);
126 } else if (*p1 == ':') {
132 } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
134 path->insert(p1 - p0, '.');
135 path->insert(p1 - p0 + 1, fileName, q1 - fileName);
136 } else if (*p1 == ':') {
139 path->append(fileName, q1 - fileName);
142 path->append(fileName, q1 - fileName);
145 if (*p1 != ']' && *p1 != ':')
147 path->append(fileName);
152 //---------- Win32 ----------
157 tmp = new GString(path);
159 tmp->append(fileName);
160 GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
167 //---------- RISCOS ----------
172 i = path->getLength();
173 path->append(fileName);
174 for (p = path->getCString() + i; *p; ++p) {
177 } else if (*p == '.') {
184 //---------- MacOS ----------
189 i = path->getLength();
190 path->append(fileName);
191 for (p = path->getCString() + i; *p; ++p) {
194 } else if (*p == '.') {
200 #elif defined(__EMX__)
201 //---------- OS/2+EMX ----------
204 // appending "." does nothing
205 if (!strcmp(fileName, "."))
208 // appending ".." goes up one directory
209 if (!strcmp(fileName, "..")) {
210 for (i = path->getLength() - 2; i >= 0; --i) {
211 if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
212 path->getChar(i) == ':')
216 if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
217 path->del(1, path->getLength() - 1);
218 } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
219 path->del(2, path->getLength() - 2);
225 if (path->getChar(i-1) == ':')
227 path->del(i, path->getLength() - i);
232 // otherwise, append "/" and new path component
233 if (path->getLength() > 0 &&
234 path->getChar(path->getLength() - 1) != '/' &&
235 path->getChar(path->getLength() - 1) != '\\')
237 path->append(fileName);
241 //---------- Unix ----------
244 // appending "." does nothing
245 if (!strcmp(fileName, "."))
248 // appending ".." goes up one directory
249 if (!strcmp(fileName, "..")) {
250 for (i = path->getLength() - 2; i >= 0; --i) {
251 if (path->getChar(i) == '/')
255 if (path->getChar(0) == '/') {
256 path->del(1, path->getLength() - 1);
262 path->del(i, path->getLength() - i);
267 // otherwise, append "/" and new path component
268 if (path->getLength() > 0 &&
269 path->getChar(path->getLength() - 1) != '/')
271 path->append(fileName);
276 GString *grabPath(char *fileName) {
278 //---------- VMS ----------
281 if ((p = strrchr(fileName, ']')))
282 return new GString(fileName, p + 1 - fileName);
283 if ((p = strrchr(fileName, ':')))
284 return new GString(fileName, p + 1 - fileName);
285 return new GString();
287 #elif defined(__EMX__) || defined(WIN32)
288 //---------- OS/2+EMX and Win32 ----------
291 if ((p = strrchr(fileName, '/')))
292 return new GString(fileName, p - fileName);
293 if ((p = strrchr(fileName, '\\')))
294 return new GString(fileName, p - fileName);
295 if ((p = strrchr(fileName, ':')))
296 return new GString(fileName, p + 1 - fileName);
297 return new GString();
300 //---------- RISCOS ----------
303 if ((p = strrchr(fileName, '.')))
304 return new GString(fileName, p - fileName);
305 return new GString();
308 //---------- MacOS ----------
311 if ((p = strrchr(fileName, ':')))
312 return new GString(fileName, p - fileName);
313 return new GString();
316 //---------- Unix ----------
319 if ((p = strrchr(fileName, '/')))
320 return new GString(fileName, p - fileName);
321 return new GString();
325 GBool isAbsolutePath(char *path) {
327 //---------- VMS ----------
328 return strchr(path, ':') ||
329 (path[0] == '[' && path[1] != '.' && path[1] != '-');
331 #elif defined(__EMX__) || defined(WIN32)
332 //---------- OS/2+EMX and Win32 ----------
333 return path[0] == '/' || path[0] == '\\' || path[1] == ':';
336 //---------- RISCOS ----------
337 return path[0] == '$';
340 //---------- MacOS ----------
341 return path[0] != ':';
344 //---------- Unix ----------
345 return path[0] == '/';
349 GString *makePathAbsolute(GString *path) {
351 //---------- VMS ----------
352 char buf[PATH_MAX+1];
354 if (!isAbsolutePath(path->getCString())) {
355 if (getcwd(buf, sizeof(buf))) {
356 path->insert(0, buf);
362 //---------- Win32 ----------
367 if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
376 //---------- RISCOS ----------
377 path->insert(0, '@');
381 //---------- MacOS ----------
386 //---------- Unix and OS/2+EMX ----------
388 char buf[PATH_MAX+1];
393 if (path->getChar(0) == '~') {
394 if (path->getChar(1) == '/' ||
396 path->getChar(1) == '\\' ||
398 path->getLength() == 1) {
404 p1 = path->getCString() + 1;
406 for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
408 for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
410 if ((n = p2 - p1) > PATH_MAX)
414 if ((pw = getpwnam(buf))) {
415 path->del(0, p2 - p1 + 1);
416 path->insert(0, pw->pw_dir);
419 } else if (!isAbsolutePath(path->getCString())) {
420 if (getcwd(buf, sizeof(buf))) {
422 path->insert(0, '/');
424 path->insert(0, buf);
431 time_t getModTime(char *fileName) {
433 //~ should implement this, but it's (currently) only used in xpdf
438 if (stat(fileName, &statBuf)) {
441 return statBuf.st_mtime;
444 static char tmpbuf[128];
445 static char* mktmpname(char*ptr) {
446 // used to be mktemp. This does remove the warnings, but
447 // It's not exactly an improvement.
448 sprintf(tmpbuf, "%08x%08x",lrand48(),lrand48());
451 GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
452 #if defined(VMS) || defined(__EMX__) || defined(WIN32) || defined(ACORN) || defined(MACOS)
453 //---------- non-Unix ----------
456 // There is a security hole here: an attacker can create a symlink
457 // with this file name after the tmpnam call and before the fopen
458 // call. I will happily accept fixes to this function for non-Unix
460 if (!(s = mktmpname(NULL))) {
463 *name = new GString(s);
465 (*name)->append(ext);
467 if (!(*f = fopen((*name)->getCString(), mode))) {
473 //---------- Unix ----------
478 if (!(s = mktmpname(NULL))) {
481 *name = new GString(s);
482 s = (*name)->getCString();
483 if ((p = strrchr(s, '.'))) {
484 (*name)->del(p - s, (*name)->getLength() - (p - s));
486 (*name)->append(ext);
487 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
490 if ((s = getenv("TMPDIR"))) {
491 *name = new GString(s);
493 *name = new GString("/tmp");
495 (*name)->append("/XXXXXX");
496 fd = mkstemp((*name)->getCString());
497 #else // HAVE_MKSTEMP
498 if (!(s = mktmpname(NULL))) {
501 *name = new GString(s);
502 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
503 #endif // HAVE_MKSTEMP
505 if (fd < 0 || !(*f = fdopen(fd, mode))) {
513 //------------------------------------------------------------------------
514 // GDir and GDirEntry
515 //------------------------------------------------------------------------
517 GDirEntry::GDirEntry(char *dirPath, char *name1, GBool doStat) {
529 name = new GString(name1);
533 if (!strcmp(name1, "-") ||
534 ((p = strrchr(name1, '.')) && !strncmp(p, ".DIR;", 5)))
538 s = new GString(dirPath);
539 appendToPath(s, name1);
541 fa = GetFileAttributes(s->getCString());
542 dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
544 if (stat(s->getCString(), &st) == 0)
545 dir = S_ISDIR(st.st_mode);
552 GDirEntry::~GDirEntry() {
556 GDir::GDir(char *name, GBool doStat1) {
557 path = new GString(name);
564 hnd = FindFirstFile(tmp->getCString(), &ffd);
571 needParent = strchr(name, '[') != NULL;
591 GDirEntry *GDir::getNextEntry() {
597 e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
598 if (hnd && !FindNextFile(hnd, &ffd)) {
608 e = new GDirEntry(path->getCString(), "-", doStat);
615 if (ent && !strcmp(ent->d_name, "."))
619 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
625 void GDir::rewind() {
633 hnd = FindFirstFile(tmp->getCString(), &ffd);
640 needParent = strchr(path->getCString(), '[') != NULL;