1 //========================================================================
5 // Miscellaneous file and directory name manipulation.
7 // Copyright 1996-2003 Glyph & Cog, LLC
9 //========================================================================
15 # include <sys/stat.h>
16 # elif !defined(ACORN)
17 # include <sys/types.h>
18 # include <sys/stat.h>
23 # if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
26 # if defined(VMS) && (__DECCXX_VER < 50200000)
33 // Some systems don't define this, so just make it something reasonably
39 //------------------------------------------------------------------------
41 GString *getHomeDir() {
43 //---------- VMS ----------
44 return new GString("SYS$LOGIN:");
46 #elif defined(__EMX__) || defined(WIN32)
47 //---------- OS/2+EMX and Win32 ----------
51 if ((s = getenv("HOME")))
54 ret = new GString(".");
58 //---------- RISCOS ----------
59 return new GString("@");
62 //---------- MacOS ----------
63 return new GString(":");
66 //---------- Unix ----------
71 if ((s = getenv("HOME"))) {
74 if ((s = getenv("USER")))
77 pw = getpwuid(getuid());
79 ret = new GString(pw->pw_dir);
81 ret = new GString(".");
87 GString *getCurrentDir() {
91 if (_getcwd2(buf, sizeof(buf)))
93 if (GetCurrentDirectory(sizeof(buf), buf))
99 if (getcwd(buf, sizeof(buf)))
101 return new GString(buf);
102 return new GString();
105 GString *appendToPath(GString *path, char *fileName) {
107 //---------- VMS ----------
108 //~ this should handle everything necessary for file
109 //~ requesters, but it's certainly not complete
113 p0 = path->getCString();
114 p1 = p0 + path->getLength() - 1;
115 if (!strcmp(fileName, "-")) {
117 for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
120 path->del(p2 - p0, p1 - p2);
121 } else if (*p1 == ':') {
127 } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
129 path->insert(p1 - p0, '.');
130 path->insert(p1 - p0 + 1, fileName, q1 - fileName);
131 } else if (*p1 == ':') {
134 path->append(fileName, q1 - fileName);
137 path->append(fileName, q1 - fileName);
140 if (*p1 != ']' && *p1 != ':')
142 path->append(fileName);
147 //---------- Win32 ----------
152 tmp = new GString(path);
154 tmp->append(fileName);
155 GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
162 //---------- RISCOS ----------
167 i = path->getLength();
168 path->append(fileName);
169 for (p = path->getCString() + i; *p; ++p) {
172 } else if (*p == '.') {
179 //---------- MacOS ----------
184 i = path->getLength();
185 path->append(fileName);
186 for (p = path->getCString() + i; *p; ++p) {
189 } else if (*p == '.') {
195 #elif defined(__EMX__)
196 //---------- OS/2+EMX ----------
199 // appending "." does nothing
200 if (!strcmp(fileName, "."))
203 // appending ".." goes up one directory
204 if (!strcmp(fileName, "..")) {
205 for (i = path->getLength() - 2; i >= 0; --i) {
206 if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
207 path->getChar(i) == ':')
211 if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
212 path->del(1, path->getLength() - 1);
213 } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
214 path->del(2, path->getLength() - 2);
220 if (path->getChar(i-1) == ':')
222 path->del(i, path->getLength() - i);
227 // otherwise, append "/" and new path component
228 if (path->getLength() > 0 &&
229 path->getChar(path->getLength() - 1) != '/' &&
230 path->getChar(path->getLength() - 1) != '\\')
232 path->append(fileName);
236 //---------- Unix ----------
239 // appending "." does nothing
240 if (!strcmp(fileName, "."))
243 // appending ".." goes up one directory
244 if (!strcmp(fileName, "..")) {
245 for (i = path->getLength() - 2; i >= 0; --i) {
246 if (path->getChar(i) == '/')
250 if (path->getChar(0) == '/') {
251 path->del(1, path->getLength() - 1);
257 path->del(i, path->getLength() - i);
262 // otherwise, append "/" and new path component
263 if (path->getLength() > 0 &&
264 path->getChar(path->getLength() - 1) != '/')
266 path->append(fileName);
271 GString *grabPath(char *fileName) {
273 //---------- VMS ----------
276 if ((p = strrchr(fileName, ']')))
277 return new GString(fileName, p + 1 - fileName);
278 if ((p = strrchr(fileName, ':')))
279 return new GString(fileName, p + 1 - fileName);
280 return new GString();
282 #elif defined(__EMX__) || defined(WIN32)
283 //---------- OS/2+EMX and Win32 ----------
286 if ((p = strrchr(fileName, '/')))
287 return new GString(fileName, p - fileName);
288 if ((p = strrchr(fileName, '\\')))
289 return new GString(fileName, p - fileName);
290 if ((p = strrchr(fileName, ':')))
291 return new GString(fileName, p + 1 - fileName);
292 return new GString();
295 //---------- RISCOS ----------
298 if ((p = strrchr(fileName, '.')))
299 return new GString(fileName, p - fileName);
300 return new GString();
303 //---------- MacOS ----------
306 if ((p = strrchr(fileName, ':')))
307 return new GString(fileName, p - fileName);
308 return new GString();
311 //---------- Unix ----------
314 if ((p = strrchr(fileName, '/')))
315 return new GString(fileName, p - fileName);
316 return new GString();
320 GBool isAbsolutePath(char *path) {
322 //---------- VMS ----------
323 return strchr(path, ':') ||
324 (path[0] == '[' && path[1] != '.' && path[1] != '-');
326 #elif defined(__EMX__) || defined(WIN32)
327 //---------- OS/2+EMX and Win32 ----------
328 return path[0] == '/' || path[0] == '\\' || path[1] == ':';
331 //---------- RISCOS ----------
332 return path[0] == '$';
335 //---------- MacOS ----------
336 return path[0] != ':';
339 //---------- Unix ----------
340 return path[0] == '/';
344 GString *makePathAbsolute(GString *path) {
346 //---------- VMS ----------
347 char buf[PATH_MAX+1];
349 if (!isAbsolutePath(path->getCString())) {
350 if (getcwd(buf, sizeof(buf))) {
351 path->insert(0, buf);
357 //---------- Win32 ----------
362 if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
371 //---------- RISCOS ----------
372 path->insert(0, '@');
376 //---------- MacOS ----------
381 //---------- Unix and OS/2+EMX ----------
383 char buf[PATH_MAX+1];
388 if (path->getChar(0) == '~') {
389 if (path->getChar(1) == '/' ||
391 path->getChar(1) == '\\' ||
393 path->getLength() == 1) {
399 p1 = path->getCString() + 1;
401 for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
403 for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
405 if ((n = p2 - p1) > PATH_MAX)
409 if ((pw = getpwnam(buf))) {
410 path->del(0, p2 - p1 + 1);
411 path->insert(0, pw->pw_dir);
414 } else if (!isAbsolutePath(path->getCString())) {
415 if (getcwd(buf, sizeof(buf))) {
417 path->insert(0, '/');
419 path->insert(0, buf);
426 time_t getModTime(char *fileName) {
428 //~ should implement this, but it's (currently) only used in xpdf
433 if (stat(fileName, &statBuf)) {
436 return statBuf.st_mtime;
440 static char* getTempDir()
443 char*dir = getenv("TMP");
444 if(!dir) dir = getenv("TEMP");
445 if(!dir) dir = getenv("tmp");
446 if(!dir) dir = getenv("temp");
447 if(!dir) dir = "C:\\";
454 char* mktmpname(char*ptr) {
455 static char tmpbuf[128];
456 char*dir = getTempDir();
461 if(l && dir[l-1]!='/' && dir[l-1]!='\\') {
469 // used to be mktemp. This does remove the warnings, but
470 // It's not exactly an improvement.
472 sprintf(ptr, "%s%s%08x%08x",dir,sep,lrand48(),lrand48());
475 sprintf(ptr, "%s%s%08x%08x",dir,sep,rand(),rand());
477 static int count = 1;
478 sprintf(ptr, "%s%s%08x%04x%04x",dir,sep,time(0),(unsigned int)tmpbuf^((unsigned int)tmpbuf)>>16,count);
486 GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
488 //---------- Win32 ----------
491 if (!(s = _tempnam(getenv("TEMP"), NULL))) {
494 *name = new GString(s);
497 (*name)->append(ext);
499 if (!(*f = fopen((*name)->getCString(), mode))) {
504 #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
505 //---------- non-Unix ----------
508 // There is a security hole here: an attacker can create a symlink
509 // with this file name after the tmpnam call and before the fopen
510 // call. I will happily accept fixes to this function for non-Unix
512 if (!(s = mktmpname(NULL))) {
515 *name = new GString(s);
517 (*name)->append(ext);
519 if (!(*f = fopen((*name)->getCString(), mode))) {
525 //---------- Unix ----------
531 if ((s = getenv("TMPDIR"))) {
532 *name = new GString(s);
534 *name = new GString("/tmp");
536 (*name)->append("/XXXXXX")->append(ext);
537 fd = mkstemps((*name)->getCString(), strlen(ext));
539 if (!(s = mktmpname(NULL))) {
542 *name = new GString(s);
543 (*name)->append(ext);
544 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
548 if ((s = getenv("TMPDIR"))) {
549 *name = new GString(s);
551 *name = new GString("/tmp");
553 (*name)->append("/XXXXXX");
554 fd = mkstemp((*name)->getCString());
555 #else // HAVE_MKSTEMP
556 if (!(s = mktmpname(NULL))) {
559 *name = new GString(s);
560 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
561 #endif // HAVE_MKSTEMP
563 if (fd < 0 || !(*f = fdopen(fd, mode))) {
571 GBool executeCommand(char *cmd) {
573 return system(cmd) ? gTrue : gFalse;
575 return system(cmd) ? gFalse : gTrue;
579 char *getLine(char *buf, int size, FILE *f) {
583 while (i < size - 1) {
584 if ((c = fgetc(f)) == EOF) {
593 if (c == '\x0a' && i < size - 1) {
595 } else if (c != EOF) {
608 //------------------------------------------------------------------------
609 // GDir and GDirEntry
610 //------------------------------------------------------------------------
612 GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
624 name = new GString(nameA);
628 if (!strcmp(nameA, "-") ||
629 ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
633 s = new GString(dirPath);
634 appendToPath(s, nameA);
636 fa = GetFileAttributes(s->getCString());
637 dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
639 if (stat(s->getCString(), &st) == 0)
640 dir = S_ISDIR(st.st_mode);
647 GDirEntry::~GDirEntry() {
651 GDir::GDir(char *name, GBool doStatA) {
652 path = new GString(name);
659 hnd = FindFirstFile(tmp->getCString(), &ffd);
666 needParent = strchr(name, '[') != NULL;
686 GDirEntry *GDir::getNextEntry() {
691 e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
692 if (hnd && !FindNextFile(hnd, &ffd)) {
706 e = new GDirEntry(path->getCString(), "-", doStat);
712 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
720 if (ent && !strcmp(ent->d_name, ".")) {
724 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
732 void GDir::rewind() {
740 hnd = FindFirstFile(tmp->getCString(), &ffd);
748 needParent = strchr(path->getCString(), '[') != NULL;