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