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