Load cups into easysw/current.
[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 #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
41 GString *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
87 GString *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
105 GString *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
271 GString *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
320 GBool 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
344 GString *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
426 time_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
441 GBool 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
526 GBool 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
535 char *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
568 GDirEntry::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
603 GDirEntry::~GDirEntry() {
604   delete name;
605 }
606
607 GDir::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
627 GDir::~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
642 GDirEntry *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
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   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 }