1 //========================================================================
5 // Miscellaneous file and directory name manipulation.
7 // Copyright 1996-2002 Glyph & Cog, LLC
9 //========================================================================
12 #include "../../config.h"
17 //# include <kpathsea/win32lib.h>
22 # include <sys/stat.h>
23 # elif !defined(ACORN)
24 # include <sys/types.h>
25 # include <sys/stat.h>
30 # if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
33 # if defined(VMS) && (__DECCXX_VER < 50200000)
40 // Some systems don't define this, so just make it something reasonably
46 //------------------------------------------------------------------------
48 GString *getHomeDir() {
50 //---------- VMS ----------
51 return new GString("SYS$LOGIN:");
53 #elif defined(__EMX__) || defined(WIN32)
54 //---------- OS/2+EMX and Win32 ----------
58 if ((s = getenv("HOME")))
61 ret = new GString(".");
65 //---------- RISCOS ----------
66 return new GString("@");
69 //---------- MacOS ----------
70 return new GString(":");
73 //---------- Unix ----------
78 if ((s = getenv("HOME"))) {
81 if ((s = getenv("USER")))
84 pw = getpwuid(getuid());
86 ret = new GString(pw->pw_dir);
88 ret = new GString(".");
94 GString *getCurrentDir() {
98 if (_getcwd2(buf, sizeof(buf)))
100 if (GetCurrentDirectory(sizeof(buf), buf))
102 if (strcpy(buf, "@"))
104 if (strcpy(buf, ":"))
106 if (getcwd(buf, sizeof(buf)))
108 return new GString(buf);
109 return new GString();
112 GString *appendToPath(GString *path, char *fileName) {
114 //---------- VMS ----------
115 //~ this should handle everything necessary for file
116 //~ requesters, but it's certainly not complete
120 p0 = path->getCString();
121 p1 = p0 + path->getLength() - 1;
122 if (!strcmp(fileName, "-")) {
124 for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
127 path->del(p2 - p0, p1 - p2);
128 } else if (*p1 == ':') {
134 } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
136 path->insert(p1 - p0, '.');
137 path->insert(p1 - p0 + 1, fileName, q1 - fileName);
138 } else if (*p1 == ':') {
141 path->append(fileName, q1 - fileName);
144 path->append(fileName, q1 - fileName);
147 if (*p1 != ']' && *p1 != ':')
149 path->append(fileName);
154 //---------- Win32 ----------
159 tmp = new GString(path);
161 tmp->append(fileName);
162 GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
169 //---------- RISCOS ----------
174 i = path->getLength();
175 path->append(fileName);
176 for (p = path->getCString() + i; *p; ++p) {
179 } else if (*p == '.') {
186 //---------- MacOS ----------
191 i = path->getLength();
192 path->append(fileName);
193 for (p = path->getCString() + i; *p; ++p) {
196 } else if (*p == '.') {
202 #elif defined(__EMX__)
203 //---------- OS/2+EMX ----------
206 // appending "." does nothing
207 if (!strcmp(fileName, "."))
210 // appending ".." goes up one directory
211 if (!strcmp(fileName, "..")) {
212 for (i = path->getLength() - 2; i >= 0; --i) {
213 if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
214 path->getChar(i) == ':')
218 if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
219 path->del(1, path->getLength() - 1);
220 } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
221 path->del(2, path->getLength() - 2);
227 if (path->getChar(i-1) == ':')
229 path->del(i, path->getLength() - i);
234 // otherwise, append "/" and new path component
235 if (path->getLength() > 0 &&
236 path->getChar(path->getLength() - 1) != '/' &&
237 path->getChar(path->getLength() - 1) != '\\')
239 path->append(fileName);
243 //---------- Unix ----------
246 // appending "." does nothing
247 if (!strcmp(fileName, "."))
250 // appending ".." goes up one directory
251 if (!strcmp(fileName, "..")) {
252 for (i = path->getLength() - 2; i >= 0; --i) {
253 if (path->getChar(i) == '/')
257 if (path->getChar(0) == '/') {
258 path->del(1, path->getLength() - 1);
264 path->del(i, path->getLength() - i);
269 // otherwise, append "/" and new path component
270 if (path->getLength() > 0 &&
271 path->getChar(path->getLength() - 1) != '/')
273 path->append(fileName);
278 GString *grabPath(char *fileName) {
280 //---------- VMS ----------
283 if ((p = strrchr(fileName, ']')))
284 return new GString(fileName, p + 1 - fileName);
285 if ((p = strrchr(fileName, ':')))
286 return new GString(fileName, p + 1 - fileName);
287 return new GString();
289 #elif defined(__EMX__) || defined(WIN32)
290 //---------- OS/2+EMX and Win32 ----------
293 if ((p = strrchr(fileName, '/')))
294 return new GString(fileName, p - fileName);
295 if ((p = strrchr(fileName, '\\')))
296 return new GString(fileName, p - fileName);
297 if ((p = strrchr(fileName, ':')))
298 return new GString(fileName, p + 1 - fileName);
299 return new GString();
302 //---------- RISCOS ----------
305 if ((p = strrchr(fileName, '.')))
306 return new GString(fileName, p - fileName);
307 return new GString();
310 //---------- MacOS ----------
313 if ((p = strrchr(fileName, ':')))
314 return new GString(fileName, p - fileName);
315 return new GString();
318 //---------- Unix ----------
321 if ((p = strrchr(fileName, '/')))
322 return new GString(fileName, p - fileName);
323 return new GString();
327 GBool isAbsolutePath(char *path) {
329 //---------- VMS ----------
330 return strchr(path, ':') ||
331 (path[0] == '[' && path[1] != '.' && path[1] != '-');
333 #elif defined(__EMX__) || defined(WIN32)
334 //---------- OS/2+EMX and Win32 ----------
335 return path[0] == '/' || path[0] == '\\' || path[1] == ':';
338 //---------- RISCOS ----------
339 return path[0] == '$';
342 //---------- MacOS ----------
343 return path[0] != ':';
346 //---------- Unix ----------
347 return path[0] == '/';
351 GString *makePathAbsolute(GString *path) {
353 //---------- VMS ----------
354 char buf[PATH_MAX+1];
356 if (!isAbsolutePath(path->getCString())) {
357 if (getcwd(buf, sizeof(buf))) {
358 path->insert(0, buf);
364 //---------- Win32 ----------
369 if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
378 //---------- RISCOS ----------
379 path->insert(0, '@');
383 //---------- MacOS ----------
388 //---------- Unix and OS/2+EMX ----------
390 char buf[PATH_MAX+1];
395 if (path->getChar(0) == '~') {
396 if (path->getChar(1) == '/' ||
398 path->getChar(1) == '\\' ||
400 path->getLength() == 1) {
406 p1 = path->getCString() + 1;
408 for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
410 for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
412 if ((n = p2 - p1) > PATH_MAX)
416 if ((pw = getpwnam(buf))) {
417 path->del(0, p2 - p1 + 1);
418 path->insert(0, pw->pw_dir);
421 } else if (!isAbsolutePath(path->getCString())) {
422 if (getcwd(buf, sizeof(buf))) {
424 path->insert(0, '/');
426 path->insert(0, buf);
433 time_t getModTime(char *fileName) {
435 //~ should implement this, but it's (currently) only used in xpdf
440 if (stat(fileName, &statBuf)) {
443 return statBuf.st_mtime;
447 static char tmpbuf[128];
449 char* mktmpname(char*ptr) {
450 // used to be mktemp. This does remove the warnings, but
451 // It's not exactly an improvement.
453 sprintf(tmpbuf, "/tmp/%08x%08x",lrand48(),lrand48());
456 sprintf(tmpbuf, "/tmp/%08x%08x",rand(),rand());
458 sprintf(tmpbuf, "/tmp/%08x%08x",time(0),(unsigned int)tmpbuf);
464 GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
466 //---------- Win32 ----------
471 if (!(s = _tempnam(getenv("TEMP"), NULL))) {
474 *name = new GString(s);
477 (*name)->append(ext);
479 if (!(*f = fopen((*name)->getCString(), mode))) {
484 #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
485 //---------- non-Unix ----------
488 // There is a security hole here: an attacker can create a symlink
489 // with this file name after the tmpnam call and before the fopen
490 // call. I will happily accept fixes to this function for non-Unix
492 if (!(s = mktmpname(NULL))) { //was: tmpnam
495 *name = new GString(s);
497 (*name)->append(ext);
499 if (!(*f = fopen((*name)->getCString(), mode))) {
505 //---------- Unix ----------
511 if ((s = getenv("TMPDIR"))) {
512 *name = new GString(s);
514 *name = new GString("/tmp");
516 (*name)->append("/XXXXXX")->append(ext);
517 fd = mkstemps((*name)->getCString(), strlen(ext));
519 if (!(s = mktmpname(NULL))) { //was: tmpnam
522 *name = new GString(s);
523 (*name)->append(ext);
524 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
528 if ((s = getenv("TMPDIR"))) {
529 *name = new GString(s);
531 *name = new GString("/tmp");
533 (*name)->append("/XXXXXX");
534 fd = mkstemp((*name)->getCString());
535 #else // HAVE_MKSTEMP
536 if (!(s = mktmpname(NULL))) { //was: tmpnam
539 *name = new GString(s);
540 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
541 #endif // HAVE_MKSTEMP
543 if (fd < 0 || !(*f = fdopen(fd, mode))) {
551 GBool executeCommand(char *cmd) {
553 return system(cmd) ? gTrue : gFalse;
555 return system(cmd) ? gFalse : gTrue;
559 char *getLine(char *buf, int size, FILE *f) {
563 while (i < size - 1) {
564 if ((c = fgetc(f)) == EOF) {
573 if (c == '\x0a' && i < size - 1) {
575 } else if (c != EOF) {
588 //------------------------------------------------------------------------
589 // GDir and GDirEntry
590 //------------------------------------------------------------------------
592 GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
604 name = new GString(nameA);
608 if (!strcmp(nameA, "-") ||
609 ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
613 s = new GString(dirPath);
614 appendToPath(s, nameA);
616 fa = GetFileAttributes(s->getCString());
617 dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
619 if (stat(s->getCString(), &st) == 0)
620 dir = S_ISDIR(st.st_mode);
627 GDirEntry::~GDirEntry() {
631 GDir::GDir(char *name, GBool doStatA) {
632 path = new GString(name);
639 hnd = FindFirstFile(tmp->getCString(), &ffd);
646 needParent = strchr(name, '[') != NULL;
666 GDirEntry *GDir::getNextEntry() {
672 e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
673 if (hnd && !FindNextFile(hnd, &ffd)) {
683 e = new GDirEntry(path->getCString(), "-", doStat);
690 if (ent && !strcmp(ent->d_name, "."))
694 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
700 void GDir::rewind() {
708 hnd = FindFirstFile(tmp->getCString(), &ffd);
715 needParent = strchr(path->getCString(), '[') != NULL;