]> git.ipfire.org Git - thirdparty/cups.git/blame - pdftops/gfile.cxx
Merge changes from 1.1 tree.
[thirdparty/cups.git] / pdftops / gfile.cxx
CommitLineData
9c72faab 1//========================================================================
2//
3// gfile.cc
4//
5// Miscellaneous file and directory name manipulation.
6//
7// Copyright 1996 Derek B. Noonburg
8//
9//========================================================================
10
11#ifdef WIN32
12 extern "C" {
9c72faab 13# ifndef _MSC_VER
14# include <kpathsea/win32lib.h>
15# endif
16 }
17#else // !WIN32
52118ca3 18# if defined(MACOS)
19# include <sys/stat.h>
20# elif !defined(ACORN)
9c72faab 21# include <sys/types.h>
22# include <sys/stat.h>
52118ca3 23# include <fcntl.h>
9c72faab 24# endif
25# include <limits.h>
26# include <string.h>
52118ca3 27# if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
9c72faab 28# include <pwd.h>
29# endif
30# if defined(VMS) && (__DECCXX_VER < 50200000)
31# include <unixlib.h>
32# endif
33#endif // WIN32
34#include "GString.h"
35#include "gfile.h"
b5cb0608 36
37#ifdef HAVE_LIBCUPS
38# include <cups/cups.h>
39#endif // HAVE_LIBCUPS
9c72faab 40
41// Some systems don't define this, so just make it something reasonably
42// large.
43#ifndef PATH_MAX
44#define PATH_MAX 1024
45#endif
46
47//------------------------------------------------------------------------
48
49GString *getHomeDir() {
50#ifdef VMS
51 //---------- VMS ----------
52 return new GString("SYS$LOGIN:");
53
54#elif defined(__EMX__) || defined(WIN32)
55 //---------- OS/2+EMX and Win32 ----------
56 char *s;
57 GString *ret;
58
59 if ((s = getenv("HOME")))
60 ret = new GString(s);
61 else
62 ret = new GString(".");
63 return ret;
64
65#elif defined(ACORN)
66 //---------- RISCOS ----------
67 return new GString("@");
68
52118ca3 69#elif defined(MACOS)
70 //---------- MacOS ----------
71 return new GString(":");
72
9c72faab 73#else
74 //---------- Unix ----------
75 char *s;
76 struct passwd *pw;
77 GString *ret;
78
79 if ((s = getenv("HOME"))) {
80 ret = new GString(s);
b5cb0608 81# ifdef HAVE_LIBCUPS
82 } else if ((s = getenv("CUPS_SERVERROOT"))) {
83 ret = new GString(s);
84# endif // HAVE_LIBCUPS
9c72faab 85 } else {
86 if ((s = getenv("USER")))
87 pw = getpwnam(s);
88 else
89 pw = getpwuid(getuid());
90 if (pw)
91 ret = new GString(pw->pw_dir);
92 else
93 ret = new GString(".");
94 }
95 return ret;
96#endif
97}
98
99GString *getCurrentDir() {
100 char buf[PATH_MAX+1];
101
102#if defined(__EMX__)
103 if (_getcwd2(buf, sizeof(buf)))
104#elif defined(WIN32)
105 if (GetCurrentDirectory(sizeof(buf), buf))
106#elif defined(ACORN)
107 if (strcpy(buf, "@"))
52118ca3 108#elif defined(MACOS)
109 if (strcpy(buf, ":"))
9c72faab 110#else
111 if (getcwd(buf, sizeof(buf)))
112#endif
113 return new GString(buf);
114 return new GString();
115}
116
b5cb0608 117GString *appendToPath(GString *path, const char *fileName) {
9c72faab 118#if defined(VMS)
119 //---------- VMS ----------
120 //~ this should handle everything necessary for file
121 //~ requesters, but it's certainly not complete
122 char *p0, *p1, *p2;
123 char *q1;
124
125 p0 = path->getCString();
126 p1 = p0 + path->getLength() - 1;
127 if (!strcmp(fileName, "-")) {
128 if (*p1 == ']') {
129 for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
130 if (*p2 == '[')
131 ++p2;
132 path->del(p2 - p0, p1 - p2);
133 } else if (*p1 == ':') {
134 path->append("[-]");
135 } else {
136 path->clear();
137 path->append("[-]");
138 }
139 } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
140 if (*p1 == ']') {
141 path->insert(p1 - p0, '.');
142 path->insert(p1 - p0 + 1, fileName, q1 - fileName);
143 } else if (*p1 == ':') {
144 path->append('[');
145 path->append(']');
146 path->append(fileName, q1 - fileName);
147 } else {
148 path->clear();
149 path->append(fileName, q1 - fileName);
150 }
151 } else {
152 if (*p1 != ']' && *p1 != ':')
153 path->clear();
154 path->append(fileName);
155 }
156 return path;
157
158#elif defined(WIN32)
159 //---------- Win32 ----------
160 GString *tmp;
161 char buf[256];
162 char *fp;
163
164 tmp = new GString(path);
165 tmp->append('/');
166 tmp->append(fileName);
167 GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
168 delete tmp;
169 path->clear();
170 path->append(buf);
171 return path;
172
173#elif defined(ACORN)
174 //---------- RISCOS ----------
175 char *p;
176 int i;
177
178 path->append(".");
179 i = path->getLength();
180 path->append(fileName);
181 for (p = path->getCString() + i; *p; ++p) {
182 if (*p == '/') {
183 *p = '.';
184 } else if (*p == '.') {
185 *p = '/';
186 }
187 }
188 return path;
189
52118ca3 190#elif defined(MACOS)
191 //---------- MacOS ----------
192 char *p;
193 int i;
194
195 path->append(":");
196 i = path->getLength();
197 path->append(fileName);
198 for (p = path->getCString() + i; *p; ++p) {
199 if (*p == '/') {
200 *p = ':';
201 } else if (*p == '.') {
202 *p = ':';
203 }
204 }
205 return path;
206
9c72faab 207#elif defined(__EMX__)
208 //---------- OS/2+EMX ----------
209 int i;
210
211 // appending "." does nothing
212 if (!strcmp(fileName, "."))
213 return path;
214
215 // appending ".." goes up one directory
216 if (!strcmp(fileName, "..")) {
217 for (i = path->getLength() - 2; i >= 0; --i) {
218 if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
219 path->getChar(i) == ':')
220 break;
221 }
222 if (i <= 0) {
223 if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
224 path->del(1, path->getLength() - 1);
225 } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
226 path->del(2, path->getLength() - 2);
227 } else {
228 path->clear();
229 path->append("..");
230 }
231 } else {
232 if (path->getChar(i-1) == ':')
233 ++i;
234 path->del(i, path->getLength() - i);
235 }
236 return path;
237 }
238
239 // otherwise, append "/" and new path component
240 if (path->getLength() > 0 &&
241 path->getChar(path->getLength() - 1) != '/' &&
242 path->getChar(path->getLength() - 1) != '\\')
243 path->append('/');
244 path->append(fileName);
245 return path;
246
247#else
248 //---------- Unix ----------
249 int i;
250
251 // appending "." does nothing
252 if (!strcmp(fileName, "."))
253 return path;
254
255 // appending ".." goes up one directory
256 if (!strcmp(fileName, "..")) {
257 for (i = path->getLength() - 2; i >= 0; --i) {
258 if (path->getChar(i) == '/')
259 break;
260 }
261 if (i <= 0) {
262 if (path->getChar(0) == '/') {
263 path->del(1, path->getLength() - 1);
264 } else {
265 path->clear();
266 path->append("..");
267 }
268 } else {
269 path->del(i, path->getLength() - i);
270 }
271 return path;
272 }
273
274 // otherwise, append "/" and new path component
275 if (path->getLength() > 0 &&
276 path->getChar(path->getLength() - 1) != '/')
277 path->append('/');
278 path->append(fileName);
279 return path;
280#endif
281}
282
b5cb0608 283GString *grabPath(const char *fileName) {
9c72faab 284#ifdef VMS
285 //---------- VMS ----------
b5cb0608 286 const char *p;
9c72faab 287
288 if ((p = strrchr(fileName, ']')))
289 return new GString(fileName, p + 1 - fileName);
290 if ((p = strrchr(fileName, ':')))
291 return new GString(fileName, p + 1 - fileName);
292 return new GString();
293
294#elif defined(__EMX__) || defined(WIN32)
295 //---------- OS/2+EMX and Win32 ----------
b5cb0608 296 const char *p;
9c72faab 297
298 if ((p = strrchr(fileName, '/')))
299 return new GString(fileName, p - fileName);
300 if ((p = strrchr(fileName, '\\')))
301 return new GString(fileName, p - fileName);
302 if ((p = strrchr(fileName, ':')))
303 return new GString(fileName, p + 1 - fileName);
304 return new GString();
305
306#elif defined(ACORN)
307 //---------- RISCOS ----------
b5cb0608 308 const char *p;
9c72faab 309
310 if ((p = strrchr(fileName, '.')))
311 return new GString(fileName, p - fileName);
312 return new GString();
313
52118ca3 314#elif defined(MACOS)
315 //---------- MacOS ----------
b5cb0608 316 const char *p;
52118ca3 317
318 if ((p = strrchr(fileName, ':')))
319 return new GString(fileName, p - fileName);
320 return new GString();
321
9c72faab 322#else
323 //---------- Unix ----------
b5cb0608 324 const char *p;
9c72faab 325
326 if ((p = strrchr(fileName, '/')))
327 return new GString(fileName, p - fileName);
328 return new GString();
329#endif
330}
331
b5cb0608 332GBool isAbsolutePath(const char *path) {
9c72faab 333#ifdef VMS
334 //---------- VMS ----------
335 return strchr(path, ':') ||
336 (path[0] == '[' && path[1] != '.' && path[1] != '-');
337
338#elif defined(__EMX__) || defined(WIN32)
339 //---------- OS/2+EMX and Win32 ----------
340 return path[0] == '/' || path[0] == '\\' || path[1] == ':';
341
342#elif defined(ACORN)
343 //---------- RISCOS ----------
344 return path[0] == '$';
345
52118ca3 346#elif defined(MACOS)
347 //---------- MacOS ----------
348 return path[0] != ':';
349
9c72faab 350#else
351 //---------- Unix ----------
352 return path[0] == '/';
353#endif
354}
355
356GString *makePathAbsolute(GString *path) {
357#ifdef VMS
358 //---------- VMS ----------
359 char buf[PATH_MAX+1];
360
361 if (!isAbsolutePath(path->getCString())) {
362 if (getcwd(buf, sizeof(buf))) {
52118ca3 363 path->insert(0, buf);
9c72faab 364 }
365 }
366 return path;
367
368#elif defined(WIN32)
369 //---------- Win32 ----------
370 char buf[_MAX_PATH];
371 char *fp;
372
373 buf[0] = '\0';
374 if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
375 path->clear();
376 return path;
377 }
378 path->clear();
379 path->append(buf);
380 return path;
381
382#elif defined(ACORN)
383 //---------- RISCOS ----------
384 path->insert(0, '@');
385 return path;
386
52118ca3 387#elif defined(MACOS)
388 //---------- MacOS ----------
389 path->del(0, 1);
390 return path;
391
9c72faab 392#else
393 //---------- Unix and OS/2+EMX ----------
394 struct passwd *pw;
395 char buf[PATH_MAX+1];
396 GString *s;
397 char *p1, *p2;
398 int n;
399
400 if (path->getChar(0) == '~') {
401 if (path->getChar(1) == '/' ||
402#ifdef __EMX__
403 path->getChar(1) == '\\' ||
404#endif
405 path->getLength() == 1) {
406 path->del(0, 1);
407 s = getHomeDir();
408 path->insert(0, s);
409 delete s;
410 } else {
411 p1 = path->getCString() + 1;
412#ifdef __EMX__
413 for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
414#else
415 for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
416#endif
417 if ((n = p2 - p1) > PATH_MAX)
418 n = PATH_MAX;
419 strncpy(buf, p1, n);
420 buf[n] = '\0';
421 if ((pw = getpwnam(buf))) {
422 path->del(0, p2 - p1 + 1);
423 path->insert(0, pw->pw_dir);
424 }
425 }
426 } else if (!isAbsolutePath(path->getCString())) {
427 if (getcwd(buf, sizeof(buf))) {
428#ifndef __EMX__
429 path->insert(0, '/');
430#endif
431 path->insert(0, buf);
432 }
433 }
434 return path;
435#endif
436}
437
b5cb0608 438time_t getModTime(const char *fileName) {
52118ca3 439#ifdef WIN32
440 //~ should implement this, but it's (currently) only used in xpdf
441 return 0;
442#else
443 struct stat statBuf;
444
445 if (stat(fileName, &statBuf)) {
446 return 0;
447 }
448 return statBuf.st_mtime;
449#endif
450}
451
b5cb0608 452GBool openTempFile(GString **name, FILE **f, const char *mode, const char *ext) {
453#ifdef HAVE_LIBCUPS
9d13ae31 454 char filename[1024]; // Name of temporary file...
455 int fd; // File descriptor...
52118ca3 456
52118ca3 457
b5cb0608 458 (void)ext;
459
9d13ae31 460 // Use the CUPS temporary file function on all platforms...
461 if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
462 return (gFalse);
463
464 // Make the file descriptor a FILE *, and copy the temp filename...
465 *f = fdopen(fd, mode);
466 *name = new GString(filename);
467
468 return (gTrue);
b5cb0608 469#elif defined(VMS) || defined(__EMX__) || defined(WIN32) || defined(ACORN) || defined(MACOS)
470 //---------- non-Unix ----------
471 char *s;
472
473 // There is a security hole here: an attacker can create a symlink
474 // with this file name after the tmpnam call and before the fopen
475 // call. I will happily accept fixes to this function for non-Unix
476 // OSs.
477 if (!(s = tmpnam(NULL))) {
478 return gFalse;
479 }
480 *name = new GString(s);
481 if (ext) {
482 (*name)->append(ext);
483 }
484 if (!(*f = fopen((*name)->getCString(), mode))) {
485 delete (*name);
486 return gFalse;
487 }
488 return gTrue;
489#else
490 //---------- Unix ----------
491 char *s, *p;
492 int fd;
493
494 if (ext) {
495 if (!(s = tmpnam(NULL))) {
496 return gFalse;
497 }
498 *name = new GString(s);
499 s = (*name)->getCString();
500 if ((p = strrchr(s, '.'))) {
501 (*name)->del(p - s, (*name)->getLength() - (p - s));
502 }
503 (*name)->append(ext);
504 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
505 } else {
506# if HAVE_MKSTEMP
507 if ((s = getenv("TMPDIR"))) {
508 *name = new GString(s);
509 } else {
510 *name = new GString("/tmp");
511 }
512 (*name)->append("/XXXXXX");
513 fd = mkstemp((*name)->getCString());
514# else // HAVE_MKSTEMP
515 if (!(s = tmpnam(NULL))) {
516 return gFalse;
517 }
518 *name = new GString(s);
519 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
520# endif // HAVE_MKSTEMP
521 }
522 if (fd < 0 || !(*f = fdopen(fd, mode))) {
523 delete *name;
524 return gFalse;
525 }
526 return gTrue;
527#endif
52118ca3 528}
529
9c72faab 530//------------------------------------------------------------------------
531// GDir and GDirEntry
532//------------------------------------------------------------------------
533
b5cb0608 534GDirEntry::GDirEntry(const char *dirPath, const char *name1, GBool doStat) {
9c72faab 535#ifdef VMS
536 char *p;
537#elif defined(WIN32)
538 int fa;
539 GString *s;
540#elif defined(ACORN)
541#else
542 struct stat st;
543 GString *s;
544#endif
545
546 name = new GString(name1);
547 dir = gFalse;
548 if (doStat) {
549#ifdef VMS
550 if (!strcmp(name1, "-") ||
551 ((p = strrchr(name1, '.')) && !strncmp(p, ".DIR;", 5)))
552 dir = gTrue;
553#elif defined(ACORN)
554#else
555 s = new GString(dirPath);
556 appendToPath(s, name1);
557#ifdef WIN32
558 fa = GetFileAttributes(s->getCString());
559 dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
560#else
561 if (stat(s->getCString(), &st) == 0)
562 dir = S_ISDIR(st.st_mode);
563#endif
564 delete s;
565#endif
566 }
567}
568
569GDirEntry::~GDirEntry() {
570 delete name;
571}
572
b5cb0608 573GDir::GDir(const char *name, GBool doStat1) {
9c72faab 574 path = new GString(name);
575 doStat = doStat1;
576#if defined(WIN32)
577 GString *tmp;
578
579 tmp = path->copy();
580 tmp->append("/*.*");
581 hnd = FindFirstFile(tmp->getCString(), &ffd);
582 delete tmp;
583#elif defined(ACORN)
52118ca3 584#elif defined(MACOS)
9c72faab 585#else
586 dir = opendir(name);
587#ifdef VMS
588 needParent = strchr(name, '[') != NULL;
589#endif
590#endif
591}
592
593GDir::~GDir() {
594 delete path;
595#if defined(WIN32)
596 if (hnd) {
597 FindClose(hnd);
598 hnd = NULL;
599 }
600#elif defined(ACORN)
52118ca3 601#elif defined(MACOS)
9c72faab 602#else
603 if (dir)
604 closedir(dir);
605#endif
606}
607
608GDirEntry *GDir::getNextEntry() {
609 struct dirent *ent;
610 GDirEntry *e;
611
612 e = NULL;
613#if defined(WIN32)
614 e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
615 if (hnd && !FindNextFile(hnd, &ffd)) {
616 FindClose(hnd);
617 hnd = NULL;
618 }
619#elif defined(ACORN)
52118ca3 620#elif defined(MACOS)
9c72faab 621#else
622 if (dir) {
623#ifdef VMS
624 if (needParent) {
625 e = new GDirEntry(path->getCString(), "-", doStat);
626 needParent = gFalse;
627 return e;
628 }
629#endif
630 ent = readdir(dir);
631#ifndef VMS
632 if (ent && !strcmp(ent->d_name, "."))
633 ent = readdir(dir);
634#endif
635 if (ent)
636 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
637 }
638#endif
639 return e;
640}
641
642void GDir::rewind() {
643#ifdef WIN32
644 GString *tmp;
645
646 if (hnd)
647 FindClose(hnd);
648 tmp = path->copy();
649 tmp->append("/*.*");
650 hnd = FindFirstFile(tmp->getCString(), &ffd);
651#elif defined(ACORN)
52118ca3 652#elif defined(MACOS)
9c72faab 653#else
654 if (dir)
655 rewinddir(dir);
656#ifdef VMS
657 needParent = strchr(path->getCString(), '[') != NULL;
658#endif
659#endif
660}