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