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 ----------
451 if (!(s = _tempnam(getenv("TEMP"), NULL))) {
454 *name = new GString(s);
457 (*name)->append(ext);
459 if (!(*f = fopen((*name)->getCString(), mode))) {
464 #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
465 //---------- non-Unix ----------
468 // There is a security hole here: an attacker can create a symlink
469 // with this file name after the tmpnam call and before the fopen
470 // call. I will happily accept fixes to this function for non-Unix
472 if (!(s = tmpnam(NULL))) {
475 *name = new GString(s);
477 (*name)->append(ext);
479 if (!(*f = fopen((*name)->getCString(), mode))) {
485 //---------- Unix ----------
491 if ((s = getenv("TMPDIR"))) {
492 *name = new GString(s);
494 *name = new GString("/tmp");
496 (*name)->append("/XXXXXX")->append(ext);
497 fd = mkstemps((*name)->getCString(), strlen(ext));
499 if (!(s = tmpnam(NULL))) {
502 *name = new GString(s);
503 (*name)->append(ext);
504 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
508 if ((s = getenv("TMPDIR"))) {
509 *name = new GString(s);
511 *name = new GString("/tmp");
513 (*name)->append("/XXXXXX");
514 fd = mkstemp((*name)->getCString());
515 #else // HAVE_MKSTEMP
516 if (!(s = tmpnam(NULL))) {
519 *name = new GString(s);
520 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
521 #endif // HAVE_MKSTEMP
523 if (fd < 0 || !(*f = fdopen(fd, mode))) {
531 GBool executeCommand(char *cmd) {
533 return system(cmd) ? gTrue : gFalse;
535 return system(cmd) ? gFalse : gTrue;
539 char *getLine(char *buf, int size, FILE *f) {
543 while (i < size - 1) {
544 if ((c = fgetc(f)) == EOF) {
553 if (c == '\x0a' && i < size - 1) {
555 } else if (c != EOF) {
568 //------------------------------------------------------------------------
569 // GDir and GDirEntry
570 //------------------------------------------------------------------------
572 GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
584 name = new GString(nameA);
588 if (!strcmp(nameA, "-") ||
589 ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
593 s = new GString(dirPath);
594 appendToPath(s, nameA);
596 fa = GetFileAttributes(s->getCString());
597 dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
599 if (stat(s->getCString(), &st) == 0)
600 dir = S_ISDIR(st.st_mode);
607 GDirEntry::~GDirEntry() {
611 GDir::GDir(char *name, GBool doStatA) {
612 path = new GString(name);
619 hnd = FindFirstFile(tmp->getCString(), &ffd);
626 needParent = strchr(name, '[') != NULL;
646 GDirEntry *GDir::getNextEntry() {
650 e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
651 if (hnd && !FindNextFile(hnd, &ffd)) {
662 e = new GDirEntry(path->getCString(), "-", doStat);
668 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
676 if (ent && !strcmp(ent->d_name, ".")) {
680 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
688 void GDir::rewind() {
696 hnd = FindFirstFile(tmp->getCString(), &ffd);
703 needParent = strchr(path->getCString(), '[') != NULL;