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 GBool
openTempFile(GString
**name
, FILE **f
, char *mode
, char *ext
) {
442 //---------- Win32 ----------
445 if (!(s
= _tempnam(getenv("TEMP"), NULL
))) {
448 *name
= new GString(s
);
451 (*name
)->append(ext
);
453 if (!(*f
= fopen((*name
)->getCString(), mode
))) {
458 #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
459 //---------- non-Unix ----------
462 // There is a security hole here: an attacker can create a symlink
463 // with this file name after the tmpnam call and before the fopen
464 // call. I will happily accept fixes to this function for non-Unix
466 if (!(s
= tmpnam(NULL
))) {
469 *name
= new GString(s
);
471 (*name
)->append(ext
);
473 if (!(*f
= fopen((*name
)->getCString(), mode
))) {
479 //---------- Unix ----------
485 if ((s
= getenv("TMPDIR"))) {
486 *name
= new GString(s
);
488 *name
= new GString("/tmp");
490 (*name
)->append("/XXXXXX")->append(ext
);
491 fd
= mkstemps((*name
)->getCString(), strlen(ext
));
493 if (!(s
= tmpnam(NULL
))) {
496 *name
= new GString(s
);
497 (*name
)->append(ext
);
498 fd
= open((*name
)->getCString(), O_WRONLY
| O_CREAT
| O_EXCL
, 0600);
502 if ((s
= getenv("TMPDIR"))) {
503 *name
= new GString(s
);
505 *name
= new GString("/tmp");
507 (*name
)->append("/XXXXXX");
508 fd
= mkstemp((*name
)->getCString());
509 #else // HAVE_MKSTEMP
510 if (!(s
= tmpnam(NULL
))) {
513 *name
= new GString(s
);
514 fd
= open((*name
)->getCString(), O_WRONLY
| O_CREAT
| O_EXCL
, 0600);
515 #endif // HAVE_MKSTEMP
517 if (fd
< 0 || !(*f
= fdopen(fd
, mode
))) {
525 GBool
executeCommand(char *cmd
) {
527 return system(cmd
) ? gTrue
: gFalse
;
529 return system(cmd
) ? gFalse
: gTrue
;
533 char *getLine(char *buf
, int size
, FILE *f
) {
537 while (i
< size
- 1) {
538 if ((c
= fgetc(f
)) == EOF
) {
547 if (c
== '\x0a' && i
< size
- 1) {
549 } else if (c
!= EOF
) {
562 //------------------------------------------------------------------------
563 // GDir and GDirEntry
564 //------------------------------------------------------------------------
566 GDirEntry::GDirEntry(char *dirPath
, char *nameA
, GBool doStat
) {
578 name
= new GString(nameA
);
582 if (!strcmp(nameA
, "-") ||
583 ((p
= strrchr(nameA
, '.')) && !strncmp(p
, ".DIR;", 5)))
587 s
= new GString(dirPath
);
588 appendToPath(s
, nameA
);
590 fa
= GetFileAttributes(s
->getCString());
591 dir
= (fa
!= 0xFFFFFFFF && (fa
& FILE_ATTRIBUTE_DIRECTORY
));
593 if (stat(s
->getCString(), &st
) == 0)
594 dir
= S_ISDIR(st
.st_mode
);
601 GDirEntry::~GDirEntry() {
605 GDir::GDir(char *name
, GBool doStatA
) {
606 path
= new GString(name
);
613 hnd
= FindFirstFile(tmp
->getCString(), &ffd
);
620 needParent
= strchr(name
, '[') != NULL
;
640 GDirEntry
*GDir::getNextEntry() {
645 e
= new GDirEntry(path
->getCString(), ffd
.cFileName
, doStat
);
646 if (hnd
&& !FindNextFile(hnd
, &ffd
)) {
660 e
= new GDirEntry(path
->getCString(), "-", doStat
);
666 e
= new GDirEntry(path
->getCString(), ent
->d_name
, doStat
);
674 if (ent
&& !strcmp(ent
->d_name
, ".")) {
678 e
= new GDirEntry(path
->getCString(), ent
->d_name
, doStat
);
686 void GDir::rewind() {
694 hnd
= FindFirstFile(tmp
->getCString(), &ffd
);
702 needParent
= strchr(path
->getCString(), '[') != NULL
;