]> www.fi.muni.cz Git - evince.git/blob - pdf/goo/gfile.cc
update
[evince.git] / pdf / goo / gfile.cc
1 //========================================================================
2 //
3 // gfile.cc
4 //
5 // Miscellaneous file and directory name manipulation.
6 //
7 // Copyright 1996-2002 Glyph & Cog, LLC
8 //
9 //========================================================================
10
11 #include <aconf.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, 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(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   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(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(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, char *mode, 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(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(char *dirPath, 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(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 }