1 //========================================================================
5 // Miscellaneous file and directory name manipulation.
7 // Copyright 1996-2003 Glyph & Cog, LLC
9 //========================================================================
13 #include <aros/debug.h>
18 # include <sys/stat.h>
19 # elif !defined(ACORN)
20 # include <sys/types.h>
21 # include <sys/stat.h>
26 # if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
29 # if defined(VMS) && (__DECCXX_VER < 50200000)
36 // Some systems don't define this, so just make it something reasonably
42 //------------------------------------------------------------------------
44 GString
*getHomeDir() {
46 //---------- VMS ----------
47 return new GString("SYS$LOGIN:");
48 #elif defined(__AROS__)
49 return new GString("progdir:");
50 #elif defined(__EMX__) || defined(WIN32)
51 //---------- OS/2+EMX and Win32 ----------
55 if ((s
= getenv("HOME")))
58 ret
= new GString(".");
62 //---------- RISCOS ----------
63 return new GString("@");
66 //---------- MacOS ----------
67 return new GString(":");
70 //---------- Unix ----------
75 if ((s
= getenv("HOME"))) {
78 if ((s
= getenv("USER")))
81 pw
= getpwuid(getuid());
83 ret
= new GString(pw
->pw_dir
);
85 ret
= new GString(".");
91 GString
*getCurrentDir() {
95 if (_getcwd2(buf
, sizeof(buf
)))
97 if (GetCurrentDirectory(sizeof(buf
), buf
))
101 if (strcpy(buf
, ":"))
103 if (getcwd(buf
, sizeof(buf
)))
105 return new GString(buf
);
106 return new GString();
109 GString
*appendToPath(GString
*path
, char *fileName
) {
111 //---------- VMS ----------
112 //~ this should handle everything necessary for file
113 //~ requesters, but it's certainly not complete
117 p0
= path
->getCString();
118 p1
= p0
+ path
->getLength() - 1;
119 if (!strcmp(fileName
, "-")) {
121 for (p2
= p1
; p2
> p0
&& *p2
!= '.' && *p2
!= '['; --p2
) ;
124 path
->del(p2
- p0
, p1
- p2
);
125 } else if (*p1
== ':') {
131 } else if ((q1
= strrchr(fileName
, '.')) && !strncmp(q1
, ".DIR;", 5)) {
133 path
->insert(p1
- p0
, '.');
134 path
->insert(p1
- p0
+ 1, fileName
, q1
- fileName
);
135 } else if (*p1
== ':') {
138 path
->append(fileName
, q1
- fileName
);
141 path
->append(fileName
, q1
- fileName
);
144 if (*p1
!= ']' && *p1
!= ':')
146 path
->append(fileName
);
151 //---------- Win32 ----------
156 tmp
= new GString(path
);
158 tmp
->append(fileName
);
159 GetFullPathName(tmp
->getCString(), sizeof(buf
), buf
, &fp
);
164 #elif defined(__AROS__)
165 //---------- AROS ------------
167 bug("Path: %s Filename: %s\n",path
->getCString(),fileName
);
168 // appending "." does nothing
169 if (!strcmp(fileName
, "."))
172 // appending ".." goes up one directory
173 if (!strcmp(fileName
, "..")) {
174 for (i
= path
->getLength() - 2; i
>= 0; --i
) {
175 if ((path
->getChar(i
) == '/') || (path
->getChar(i
) == ':'))
180 path
->append("sys:");
183 path
->del(i
, path
->getLength() - i
);
189 // otherwise, append "/" and new path component
190 if (path
->getLength() > 0 &&
191 (path
->getChar(path
->getLength() - 1) != ':')||(path
->getChar(path
->getLength() - 1) != '/'))
193 path
->append(fileName
);
198 //---------- RISCOS ----------
203 i
= path
->getLength();
204 path
->append(fileName
);
205 for (p
= path
->getCString() + i
; *p
; ++p
) {
208 } else if (*p
== '.') {
215 //---------- MacOS ----------
220 i
= path
->getLength();
221 path
->append(fileName
);
222 for (p
= path
->getCString() + i
; *p
; ++p
) {
225 } else if (*p
== '.') {
231 #elif defined(__EMX__)
232 //---------- OS/2+EMX ----------
235 // appending "." does nothing
236 if (!strcmp(fileName
, "."))
239 // appending ".." goes up one directory
240 if (!strcmp(fileName
, "..")) {
241 for (i
= path
->getLength() - 2; i
>= 0; --i
) {
242 if (path
->getChar(i
) == '/' || path
->getChar(i
) == '\\' ||
243 path
->getChar(i
) == ':')
247 if (path
->getChar(0) == '/' || path
->getChar(0) == '\\') {
248 path
->del(1, path
->getLength() - 1);
249 } else if (path
->getLength() >= 2 && path
->getChar(1) == ':') {
250 path
->del(2, path
->getLength() - 2);
256 if (path
->getChar(i
-1) == ':')
258 path
->del(i
, path
->getLength() - i
);
263 // otherwise, append "/" and new path component
264 if (path
->getLength() > 0 &&
265 path
->getChar(path
->getLength() - 1) != '/' &&
266 path
->getChar(path
->getLength() - 1) != '\\')
268 path
->append(fileName
);
272 //---------- Unix ----------
274 // appending "." does nothing
275 if (!strcmp(fileName
, "."))
278 // appending ".." goes up one directory
279 if (!strcmp(fileName
, "..")) {
280 for (i
= path
->getLength() - 2; i
>= 0; --i
) {
281 if (path
->getChar(i
) == '/')
285 if (path
->getChar(0) == '/') {
286 path
->del(1, path
->getLength() - 1);
292 path
->del(i
, path
->getLength() - i
);
297 // otherwise, append "/" and new path component
298 if (path
->getLength() > 0 &&
299 path
->getChar(path
->getLength() - 1) != '/')
301 path
->append(fileName
);
307 GString
*grabPath(char *fileName
) {
309 //---------- VMS ----------
312 if ((p
= strrchr(fileName
, ']')))
313 return new GString(fileName
, p
+ 1 - fileName
);
314 if ((p
= strrchr(fileName
, ':')))
315 return new GString(fileName
, p
+ 1 - fileName
);
316 return new GString();
318 #elif defined(__EMX__) || defined(WIN32)
319 //---------- OS/2+EMX and Win32 ----------
322 if ((p
= strrchr(fileName
, '/')))
323 return new GString(fileName
, p
- fileName
);
324 if ((p
= strrchr(fileName
, '\\')))
325 return new GString(fileName
, p
- fileName
);
326 if ((p
= strrchr(fileName
, ':')))
327 return new GString(fileName
, p
+ 1 - fileName
);
328 return new GString();
331 //---------- RISCOS ----------
334 if ((p
= strrchr(fileName
, '.')))
335 return new GString(fileName
, p
- fileName
);
336 return new GString();
339 //---------- MacOS ----------
342 if ((p
= strrchr(fileName
, ':')))
343 return new GString(fileName
, p
- fileName
);
344 return new GString();
345 #elif defined(__AROS__)
346 //---------- AROS ---------------
348 if ((p
= strrchr(fileName
, '/')))
349 return new GString(fileName
, p
+ 1 - fileName
);
350 if ((p
= strrchr(fileName
, ':')))
351 return new GString(fileName
, p
+ 1 - fileName
);
352 return new GString();
355 //---------- Unix ----------
358 if ((p
= strrchr(fileName
, '/'))) {
360 return new GString(fileName
, p
- fileName
);
362 return new GString();
366 GBool
isAbsolutePath(char *path
) {
368 //---------- VMS ----------
369 return strchr(path
, ':') ||
370 (path
[0] == '[' && path
[1] != '.' && path
[1] != '-');
372 #elif defined(__EMX__) || defined(WIN32)
373 //---------- OS/2+EMX and Win32 ----------
374 return path
[0] == '/' || path
[0] == '\\' || path
[1] == ':';
377 //---------- RISCOS ----------
378 return path
[0] == '$';
381 //---------- MacOS ----------
382 return path
[0] != ':';
383 #elif defined(__AROS__)
384 return strchr(path
, ':')!=NULL
;
386 //---------- Unix ----------
387 return path
[0] == '/';
391 GString
*makePathAbsolute(GString
*path
) {
393 //---------- VMS ----------
394 char buf
[PATH_MAX
+1];
396 if (!isAbsolutePath(path
->getCString())) {
397 if (getcwd(buf
, sizeof(buf
))) {
398 path
->insert(0, buf
);
404 //---------- Win32 ----------
409 if (!GetFullPathName(path
->getCString(), _MAX_PATH
, buf
, &fp
)) {
418 //---------- RISCOS ----------
419 path
->insert(0, '@');
423 //---------- MacOS ----------
427 //---------- AROS ----------
429 char buf
[PATH_MAX
+1];
434 if (path
->getChar(0) == '~') {
435 if (path
->getChar(1) == '/' ||
436 path
->getLength() == 1) {
442 p1
= path
->getCString() + 1;
443 for (p2
= p1
; *p2
&& *p2
!= '/'; ++p2
) ;
444 if ((n
= p2
- p1
) > PATH_MAX
)
448 if ((pw
= getpwnam(buf
))) {
449 path
->del(0, p2
- p1
+ 1);
450 path
->insert(0, pw
->pw_dir
);
453 } else if (!isAbsolutePath(path
->getCString())) {
454 if (getcwd(buf
, sizeof(buf
))) {
455 path
->insert(0, '/');
456 path
->insert(0, buf
);
463 //---------- Unix and OS/2+EMX ----------
465 char buf
[PATH_MAX
+1];
470 if (path
->getChar(0) == '~') {
471 if (path
->getChar(1) == '/' ||
473 path
->getChar(1) == '\\' ||
475 path
->getLength() == 1) {
481 p1
= path
->getCString() + 1;
483 for (p2
= p1
; *p2
&& *p2
!= '/' && *p2
!= '\\'; ++p2
) ;
485 for (p2
= p1
; *p2
&& *p2
!= '/'; ++p2
) ;
487 if ((n
= p2
- p1
) > PATH_MAX
)
491 if ((pw
= getpwnam(buf
))) {
492 path
->del(0, p2
- p1
+ 1);
493 path
->insert(0, pw
->pw_dir
);
496 } else if (!isAbsolutePath(path
->getCString())) {
497 if (getcwd(buf
, sizeof(buf
))) {
499 path
->insert(0, '/');
501 path
->insert(0, buf
);
509 time_t getModTime(char *fileName
) {
511 //~ should implement this, but it's (currently) only used in xpdf
516 if (stat(fileName
, &statBuf
)) {
519 return statBuf
.st_mtime
;
523 GBool
openTempFile(GString
**name
, FILE **f
, char *mode
, char *ext
) {
525 //---------- Win32 ----------
532 // this has the standard race condition problem, but I haven't found
533 // a better way to generate temp file names with extensions on
535 if ((tempDir
= getenv("TEMP"))) {
536 s
= new GString(tempDir
);
543 for (i
= 0; i
< 1000; ++i
) {
544 sprintf(buf
, "%d", t
+ i
);
545 s2
= s
->copy()->append(buf
);
549 if (!(f2
= fopen(s2
->getCString(), "r"))) {
550 if (!(f2
= fopen(s2
->getCString(), mode
))) {
565 #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
566 //---------- non-Unix ----------
569 // There is a security hole here: an attacker can create a symlink
570 // with this file name after the tmpnam call and before the fopen
571 // call. I will happily accept fixes to this function for non-Unix
573 if (!(s
= tmpnam(NULL
))) {
576 *name
= new GString(s
);
578 (*name
)->append(ext
);
581 if (!(*f
= fopen((*name
)->getCString(), mode
))) {
587 //---------- Unix ----------
593 if ((s
= getenv("TMPDIR"))) {
594 *name
= new GString(s
);
596 *name
= new GString("T:");
598 (*name
)->append("XXXXXX")->append(ext
);
599 fd
= mkstemps((*name
)->getCString(), strlen(ext
));
601 if (!(s
= tmpnam(NULL
))) {
604 *name
= new GString(s
);
605 (*name
)->append(ext
);
606 fd
= open((*name
)->getCString(), O_WRONLY
| O_CREAT
| O_EXCL
, 0600);
610 if ((s
= getenv("TMPDIR"))) {
611 *name
= new GString(s
);
613 *name
= new GString("T:");
615 (*name
)->append("XXXXXX");
616 fd
= mkstemp((*name
)->getCString());
617 #else // HAVE_MKSTEMP
618 if (!(s
= tmpnam(NULL
))) {
621 *name
= new GString(s
);
622 fd
= open((*name
)->getCString(), O_WRONLY
| O_CREAT
| O_EXCL
, 0600);
623 #endif // HAVE_MKSTEMP
625 if (fd
< 0 || !(*f
= fdopen(fd
, mode
))) {
634 GBool
executeCommand(char *cmd
) {
636 return system(cmd
) ? gTrue
: gFalse
;
638 return system(cmd
) ? gFalse
: gTrue
;
642 char *getLine(char *buf
, int size
, FILE *f
) {
646 while (i
< size
- 1) {
647 if ((c
= fgetc(f
)) == EOF
) {
656 if (c
== '\x0a' && i
< size
- 1) {
658 } else if (c
!= EOF
) {
671 //------------------------------------------------------------------------
672 // GDir and GDirEntry
673 //------------------------------------------------------------------------
675 GDirEntry::GDirEntry(char *dirPath
, char *nameA
, GBool doStat
) {
687 name
= new GString(nameA
);
691 if (!strcmp(nameA
, "-") ||
692 ((p
= strrchr(nameA
, '.')) && !strncmp(p
, ".DIR;", 5)))
696 s
= new GString(dirPath
);
697 appendToPath(s
, nameA
);
699 fa
= GetFileAttributes(s
->getCString());
700 dir
= (fa
!= 0xFFFFFFFF && (fa
& FILE_ATTRIBUTE_DIRECTORY
));
702 if (stat(s
->getCString(), &st
) == 0)
703 dir
= S_ISDIR(st
.st_mode
);
710 GDirEntry::~GDirEntry() {
714 GDir::GDir(char *name
, GBool doStatA
) {
715 path
= new GString(name
);
722 hnd
= FindFirstFile(tmp
->getCString(), &ffd
);
729 needParent
= strchr(name
, '[') != NULL
;
749 GDirEntry
*GDir::getNextEntry() {
754 e
= new GDirEntry(path
->getCString(), ffd
.cFileName
, doStat
);
755 if (hnd
&& !FindNextFile(hnd
, &ffd
)) {
769 e
= new GDirEntry(path
->getCString(), "-", doStat
);
775 e
= new GDirEntry(path
->getCString(), ent
->d_name
, doStat
);
782 ent
= (struct dirent
*)readdir(dir
);
783 if (ent
&& !strcmp(ent
->d_name
, ".")) {
784 ent
= (struct dirent
*)readdir(dir
);
787 e
= new GDirEntry(path
->getCString(), ent
->d_name
, doStat
);
795 void GDir::rewind() {
803 hnd
= FindFirstFile(tmp
->getCString(), &ffd
);
811 needParent
= strchr(path
->getCString(), '[') != NULL
;