1 //========================================================================
5 // Miscellaneous file and directory name manipulation.
7 // Copyright 1996-2002 Glyph & Cog, LLC
9 //========================================================================
16 # include <kpathsea/win32lib.h>
21 # include <sys/stat.h>
22 # elif !defined(ACORN)
23 # include <sys/types.h>
24 # include <sys/stat.h>
29 # if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
32 # if defined(VMS) && (__DECCXX_VER < 50200000)
39 // Some systems don't define this, so just make it something reasonably
45 //------------------------------------------------------------------------
47 GString *getHomeDir() {
49 //---------- VMS ----------
50 return new GString("SYS$LOGIN:");
52 #elif defined(__EMX__) || defined(WIN32)
53 //---------- OS/2+EMX and Win32 ----------
57 if ((s = getenv("HOME")))
60 ret = new GString(".");
64 //---------- RISCOS ----------
65 return new GString("@");
68 //---------- MacOS ----------
69 return new GString(":");
72 //---------- Unix ----------
77 if ((s = getenv("HOME"))) {
80 if ((s = getenv("USER")))
83 pw = getpwuid(getuid());
85 ret = new GString(pw->pw_dir);
87 ret = new GString(".");
93 GString *getCurrentDir() {
97 if (_getcwd2(buf, sizeof(buf)))
99 if (GetCurrentDirectory(sizeof(buf), buf))
101 if (strcpy(buf, "@"))
103 if (strcpy(buf, ":"))
105 if (getcwd(buf, sizeof(buf)))
107 return new GString(buf);
108 return new GString();
111 GString *appendToPath(GString *path, char *fileName) {
113 //---------- VMS ----------
114 //~ this should handle everything necessary for file
115 //~ requesters, but it's certainly not complete
119 p0 = path->getCString();
120 p1 = p0 + path->getLength() - 1;
121 if (!strcmp(fileName, "-")) {
123 for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
126 path->del(p2 - p0, p1 - p2);
127 } else if (*p1 == ':') {
133 } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
135 path->insert(p1 - p0, '.');
136 path->insert(p1 - p0 + 1, fileName, q1 - fileName);
137 } else if (*p1 == ':') {
140 path->append(fileName, q1 - fileName);
143 path->append(fileName, q1 - fileName);
146 if (*p1 != ']' && *p1 != ':')
148 path->append(fileName);
153 //---------- Win32 ----------
158 tmp = new GString(path);
160 tmp->append(fileName);
161 GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
168 //---------- RISCOS ----------
173 i = path->getLength();
174 path->append(fileName);
175 for (p = path->getCString() + i; *p; ++p) {
178 } else if (*p == '.') {
185 //---------- MacOS ----------
190 i = path->getLength();
191 path->append(fileName);
192 for (p = path->getCString() + i; *p; ++p) {
195 } else if (*p == '.') {
201 #elif defined(__EMX__)
202 //---------- OS/2+EMX ----------
205 // appending "." does nothing
206 if (!strcmp(fileName, "."))
209 // appending ".." goes up one directory
210 if (!strcmp(fileName, "..")) {
211 for (i = path->getLength() - 2; i >= 0; --i) {
212 if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
213 path->getChar(i) == ':')
217 if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
218 path->del(1, path->getLength() - 1);
219 } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
220 path->del(2, path->getLength() - 2);
226 if (path->getChar(i-1) == ':')
228 path->del(i, path->getLength() - i);
233 // otherwise, append "/" and new path component
234 if (path->getLength() > 0 &&
235 path->getChar(path->getLength() - 1) != '/' &&
236 path->getChar(path->getLength() - 1) != '\\')
238 path->append(fileName);
242 //---------- Unix ----------
245 // appending "." does nothing
246 if (!strcmp(fileName, "."))
249 // appending ".." goes up one directory
250 if (!strcmp(fileName, "..")) {
251 for (i = path->getLength() - 2; i >= 0; --i) {
252 if (path->getChar(i) == '/')
256 if (path->getChar(0) == '/') {
257 path->del(1, path->getLength() - 1);
263 path->del(i, path->getLength() - i);
268 // otherwise, append "/" and new path component
269 if (path->getLength() > 0 &&
270 path->getChar(path->getLength() - 1) != '/')
272 path->append(fileName);
277 GString *grabPath(char *fileName) {
279 //---------- VMS ----------
282 if ((p = strrchr(fileName, ']')))
283 return new GString(fileName, p + 1 - fileName);
284 if ((p = strrchr(fileName, ':')))
285 return new GString(fileName, p + 1 - fileName);
286 return new GString();
288 #elif defined(__EMX__) || defined(WIN32)
289 //---------- OS/2+EMX and Win32 ----------
292 if ((p = strrchr(fileName, '/')))
293 return new GString(fileName, p - fileName);
294 if ((p = strrchr(fileName, '\\')))
295 return new GString(fileName, p - fileName);
296 if ((p = strrchr(fileName, ':')))
297 return new GString(fileName, p + 1 - fileName);
298 return new GString();
301 //---------- RISCOS ----------
304 if ((p = strrchr(fileName, '.')))
305 return new GString(fileName, p - fileName);
306 return new GString();
309 //---------- MacOS ----------
312 if ((p = strrchr(fileName, ':')))
313 return new GString(fileName, p - fileName);
314 return new GString();
317 //---------- Unix ----------
320 if ((p = strrchr(fileName, '/')))
321 return new GString(fileName, p - fileName);
322 return new GString();
326 GBool isAbsolutePath(char *path) {
328 //---------- VMS ----------
329 return strchr(path, ':') ||
330 (path[0] == '[' && path[1] != '.' && path[1] != '-');
332 #elif defined(__EMX__) || defined(WIN32)
333 //---------- OS/2+EMX and Win32 ----------
334 return path[0] == '/' || path[0] == '\\' || path[1] == ':';
337 //---------- RISCOS ----------
338 return path[0] == '$';
341 //---------- MacOS ----------
342 return path[0] != ':';
345 //---------- Unix ----------
346 return path[0] == '/';
350 GString *makePathAbsolute(GString *path) {
352 //---------- VMS ----------
353 char buf[PATH_MAX+1];
355 if (!isAbsolutePath(path->getCString())) {
356 if (getcwd(buf, sizeof(buf))) {
357 path->insert(0, buf);
363 //---------- Win32 ----------
368 if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
377 //---------- RISCOS ----------
378 path->insert(0, '@');
382 //---------- MacOS ----------
387 //---------- Unix and OS/2+EMX ----------
389 char buf[PATH_MAX+1];
394 if (path->getChar(0) == '~') {
395 if (path->getChar(1) == '/' ||
397 path->getChar(1) == '\\' ||
399 path->getLength() == 1) {
405 p1 = path->getCString() + 1;
407 for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
409 for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
411 if ((n = p2 - p1) > PATH_MAX)
415 if ((pw = getpwnam(buf))) {
416 path->del(0, p2 - p1 + 1);
417 path->insert(0, pw->pw_dir);
420 } else if (!isAbsolutePath(path->getCString())) {
421 if (getcwd(buf, sizeof(buf))) {
423 path->insert(0, '/');
425 path->insert(0, buf);
432 time_t getModTime(char *fileName) {
434 //~ should implement this, but it's (currently) only used in xpdf
439 if (stat(fileName, &statBuf)) {
442 return statBuf.st_mtime;
446 GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
448 //---------- Win32 ----------
453 if (!(s = _tempnam(getenv("TEMP"), NULL))) {
456 *name = new GString(s);
459 (*name)->append(ext);
461 if (!(*f = fopen((*name)->getCString(), mode))) {
466 #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
467 //---------- non-Unix ----------
470 // There is a security hole here: an attacker can create a symlink
471 // with this file name after the tmpnam call and before the fopen
472 // call. I will happily accept fixes to this function for non-Unix
474 if (!(s = tmpnam(NULL))) {
477 *name = new GString(s);
479 (*name)->append(ext);
481 if (!(*f = fopen((*name)->getCString(), mode))) {
487 //---------- Unix ----------
493 if ((s = getenv("TMPDIR"))) {
494 *name = new GString(s);
496 *name = new GString("/tmp");
498 (*name)->append("/XXXXXX")->append(ext);
499 fd = mkstemps((*name)->getCString(), strlen(ext));
501 if (!(s = tmpnam(NULL))) {
504 *name = new GString(s);
505 (*name)->append(ext);
506 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
510 if ((s = getenv("TMPDIR"))) {
511 *name = new GString(s);
513 *name = new GString("/tmp");
515 (*name)->append("/XXXXXX");
516 fd = mkstemp((*name)->getCString());
517 #else // HAVE_MKSTEMP
518 if (!(s = tmpnam(NULL))) {
521 *name = new GString(s);
522 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
523 #endif // HAVE_MKSTEMP
525 if (fd < 0 || !(*f = fdopen(fd, mode))) {
533 GBool executeCommand(char *cmd) {
535 return system(cmd) ? gTrue : gFalse;
537 return system(cmd) ? gFalse : gTrue;
541 char *getLine(char *buf, int size, FILE *f) {
545 while (i < size - 1) {
546 if ((c = fgetc(f)) == EOF) {
555 if (c == '\x0a' && i < size - 1) {
557 } else if (c != EOF) {
570 //------------------------------------------------------------------------
571 // GDir and GDirEntry
572 //------------------------------------------------------------------------
574 GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
586 name = new GString(nameA);
590 if (!strcmp(nameA, "-") ||
591 ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
595 s = new GString(dirPath);
596 appendToPath(s, nameA);
598 fa = GetFileAttributes(s->getCString());
599 dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
601 if (stat(s->getCString(), &st) == 0)
602 dir = S_ISDIR(st.st_mode);
609 GDirEntry::~GDirEntry() {
613 GDir::GDir(char *name, GBool doStatA) {
614 path = new GString(name);
621 hnd = FindFirstFile(tmp->getCString(), &ffd);
628 needParent = strchr(name, '[') != NULL;
648 GDirEntry *GDir::getNextEntry() {
654 e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
655 if (hnd && !FindNextFile(hnd, &ffd)) {
665 e = new GDirEntry(path->getCString(), "-", doStat);
672 if (ent && !strcmp(ent->d_name, "."))
676 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
682 void GDir::rewind() {
690 hnd = FindFirstFile(tmp->getCString(), &ffd);
697 needParent = strchr(path->getCString(), '[') != NULL;