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, const 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(const 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(const 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(const 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, const 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(const 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(const char *dirPath, const 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(const 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;