source: trunk/poppler/mypoppler/goo/gfile.cc @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 16 years ago

First import

File size: 15.9 KB
Line 
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) && !defined(OS2)
24#    include <pwd.h>
25#  endif
26#  if defined(VMS) && (__DECCXX_VER < 50200000)
27#    include <unixlib.h>
28#  endif
29#endif // WIN32
30#include "GooString.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
41GooString *getHomeDir() {
42#ifdef VMS
43  //---------- VMS ----------
44  return new GooString("SYS$LOGIN:");
45
46#elif defined(__EMX__) || defined(WIN32) || defined(OS2)
47  //---------- OS/2+EMX and Win32 ----------
48  char *s;
49  GooString *ret;
50
51  if ((s = getenv("HOME")))
52    ret = new GooString(s);
53  else
54    ret = new GooString(".");
55  return ret;
56
57#elif defined(ACORN)
58  //---------- RISCOS ----------
59  return new GooString("@");
60
61#elif defined(MACOS)
62  //---------- MacOS ----------
63  return new GooString(":");
64
65#else
66  //---------- Unix ----------
67  char *s;
68  struct passwd *pw;
69  GooString *ret;
70
71  if ((s = getenv("HOME"))) {
72    ret = new GooString(s);
73  } else {
74    if ((s = getenv("USER")))
75      pw = getpwnam(s);
76    else
77      pw = getpwuid(getuid());
78    if (pw)
79      ret = new GooString(pw->pw_dir);
80    else
81      ret = new GooString(".");
82  }
83  return ret;
84#endif
85}
86
87GooString *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 GooString(buf);
102  return new GooString();
103}
104
105GooString *appendToPath(GooString *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  GooString *tmp;
149  char buf[256];
150  char *fp;
151
152  tmp = new GooString(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__) || defined(OS2)
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
271GooString *grabPath(char *fileName) {
272#ifdef VMS
273  //---------- VMS ----------
274  char *p;
275
276  if ((p = strrchr(fileName, ']')))
277    return new GooString(fileName, p + 1 - fileName);
278  if ((p = strrchr(fileName, ':')))
279    return new GooString(fileName, p + 1 - fileName);
280  return new GooString();
281
282#elif defined(__EMX__) || defined(WIN32) || defined(OS2)
283  //---------- OS/2+EMX and Win32 ----------
284  char *p;
285
286  if ((p = strrchr(fileName, '/')))
287    return new GooString(fileName, p - fileName);
288  if ((p = strrchr(fileName, '\\')))
289    return new GooString(fileName, p - fileName);
290  if ((p = strrchr(fileName, ':')))
291    return new GooString(fileName, p + 1 - fileName);
292  return new GooString();
293
294#elif defined(ACORN)
295  //---------- RISCOS ----------
296  char *p;
297
298  if ((p = strrchr(fileName, '.')))
299    return new GooString(fileName, p - fileName);
300  return new GooString();
301
302#elif defined(MACOS)
303  //---------- MacOS ----------
304  char *p;
305
306  if ((p = strrchr(fileName, ':')))
307    return new GooString(fileName, p - fileName);
308  return new GooString();
309
310#else
311  //---------- Unix ----------
312  char *p;
313
314  if ((p = strrchr(fileName, '/')))
315    return new GooString(fileName, p - fileName);
316  return new GooString();
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) || defined(OS2)
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
344GooString *makePathAbsolute(GooString *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#elif defined(OS2)
381  //---------- OS/2 -----------
382  char buf[_MAX_PATH];
383  buf[0] = '\0';
384  if (!_fullpath( buf, path->getCString(), _MAX_PATH ) ) {
385    path->clear();
386    return path;
387  }
388  path->clear();
389  path->append(buf);
390  return path;
391 
392#else
393  //---------- Unix and OS/2+EMX ----------
394  struct passwd *pw;
395  char buf[PATH_MAX+1];
396  GooString *s;
397  char *p1, *p2;
398  int n;
399
400  if (path->getChar(0) == '~') {
401    if (path->getChar(1) == '/' ||
402#ifdef __EMX__
403        path->getChar(1) == '\\' ||
404#endif
405        path->getLength() == 1) {
406      path->del(0, 1);
407      s = getHomeDir();
408      path->insert(0, s);
409      delete s;
410    } else {
411      p1 = path->getCString() + 1;
412#ifdef __EMX__
413      for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
414#else
415      for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
416#endif
417      if ((n = p2 - p1) > PATH_MAX)
418        n = PATH_MAX;
419      strncpy(buf, p1, n);
420      buf[n] = '\0';
421      if ((pw = getpwnam(buf))) {
422        path->del(0, p2 - p1 + 1);
423        path->insert(0, pw->pw_dir);
424      }
425    }
426  } else if (!isAbsolutePath(path->getCString())) {
427    if (getcwd(buf, sizeof(buf))) {
428#ifndef __EMX__
429      path->insert(0, '/');
430#endif
431      path->insert(0, buf);
432    }
433  }
434  return path;
435#endif
436}
437
438time_t getModTime(char *fileName) {
439#ifdef WIN32
440  //~ should implement this, but it's (currently) only used in xpdf
441  return 0;
442#else
443  struct stat statBuf;
444
445  if (stat(fileName, &statBuf)) {
446    return 0;
447  }
448  return statBuf.st_mtime;
449#endif
450}
451
452GBool openTempFile(GooString **name, FILE **f, char *mode, char *ext) {
453#if defined(WIN32)
454  //---------- Win32 ----------
455  char *s;
456
457  if (!(s = _tempnam(getenv("TEMP"), NULL))) {
458    return gFalse;
459  }
460  *name = new GooString(s);
461  free(s);
462  if (ext) {
463    (*name)->append(ext);
464  }
465  if (!(*f = fopen((*name)->getCString(), mode))) {
466    delete (*name);
467    return gFalse;
468  }
469  return gTrue;
470#elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS) || defined(OS2)
471  //---------- non-Unix ----------
472  char *s;
473
474  // There is a security hole here: an attacker can create a symlink
475  // with this file name after the tmpnam call and before the fopen
476  // call.  I will happily accept fixes to this function for non-Unix
477  // OSs.
478  if (!(s = tmpnam(NULL))) {
479    return gFalse;
480  }
481  *name = new GooString(s);
482  if (ext) {
483    (*name)->append(ext);
484  }
485  if (!(*f = fopen((*name)->getCString(), mode))) {
486    delete (*name);
487    return gFalse;
488  }
489  return gTrue;
490#else
491  //---------- Unix ----------
492  char *s;
493  int fd;
494
495  if (ext) {
496#if HAVE_MKSTEMPS
497    if ((s = getenv("TMPDIR"))) {
498      *name = new GooString(s);
499    } else {
500      *name = new GooString("/tmp");
501    }
502    (*name)->append("/XXXXXX")->append(ext);
503    fd = mkstemps((*name)->getCString(), strlen(ext));
504#elif defined(HAVE_MKSTEMP)
505    if ((s = getenv("TMPDIR"))) {
506      *name = new GooString(s);
507    } else {
508      *name = new GooString("/tmp");
509    }
510    (*name)->append("/XXXXXX")->append(ext);
511    fd = mkstemp((*name)->getCString());
512#else
513    if (!(s = tmpnam(NULL))) {
514      return gFalse;
515    }
516    *name = new GooString(s);
517    (*name)->append(ext);
518    fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
519#endif
520  } else {
521#if HAVE_MKSTEMP
522    if ((s = getenv("TMPDIR"))) {
523      *name = new GooString(s);
524    } else {
525      *name = new GooString("/tmp");
526    }
527    (*name)->append("/XXXXXX");
528    fd = mkstemp((*name)->getCString());
529#else // HAVE_MKSTEMP
530    if (!(s = tmpnam(NULL))) {
531      return gFalse;
532    }
533    *name = new GooString(s);
534    fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
535#endif // HAVE_MKSTEMP
536  }
537  if (fd < 0 || !(*f = fdopen(fd, mode))) {
538    delete *name;
539    return gFalse;
540  }
541  return gTrue;
542#endif
543}
544
545GBool executeCommand(char *cmd) {
546#ifdef VMS
547  return system(cmd) ? gTrue : gFalse;
548#else
549  return system(cmd) ? gFalse : gTrue;
550#endif
551}
552
553char *getLine(char *buf, int size, FILE *f) {
554  int c, i;
555
556  i = 0;
557  while (i < size - 1) {
558    if ((c = fgetc(f)) == EOF) {
559      break;
560    }
561    buf[i++] = (char)c;
562    if (c == '\x0a') {
563      break;
564    }
565    if (c == '\x0d') {
566      c = fgetc(f);
567      if (c == '\x0a' && i < size - 1) {
568        buf[i++] = (char)c;
569      } else if (c != EOF) {
570        ungetc(c, f);
571      }
572      break;
573    }
574  }
575  buf[i] = '\0';
576  if (i == 0) {
577    return NULL;
578  }
579  return buf;
580}
581
582//------------------------------------------------------------------------
583// GDir and GDirEntry
584//------------------------------------------------------------------------
585
586GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
587#ifdef VMS
588  char *p;
589#elif defined(WIN32)
590  int fa;
591  GooString *s;
592#elif defined(ACORN)
593#else
594  struct stat st;
595  GooString *s;
596#endif
597
598  name = new GooString(nameA);
599  dir = gFalse;
600  if (doStat) {
601#ifdef VMS
602    if (!strcmp(nameA, "-") ||
603        ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
604      dir = gTrue;
605#elif defined(ACORN)
606#else
607    s = new GooString(dirPath);
608    appendToPath(s, nameA);
609#ifdef WIN32
610    fa = GetFileAttributes(s->getCString());
611    dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
612#else
613    if (stat(s->getCString(), &st) == 0)
614      dir = S_ISDIR(st.st_mode);
615#endif
616    delete s;
617#endif
618  }
619}
620
621GDirEntry::~GDirEntry() {
622  delete name;
623}
624
625GDir::GDir(char *name, GBool doStatA) {
626  path = new GooString(name);
627  doStat = doStatA;
628#if defined(WIN32)
629  GooString *tmp;
630
631  tmp = path->copy();
632  tmp->append("/*.*");
633  hnd = FindFirstFile(tmp->getCString(), &ffd);
634  delete tmp;
635#elif defined(ACORN)
636#elif defined(MACOS)
637#else
638  dir = opendir(name);
639#ifdef VMS
640  needParent = strchr(name, '[') != NULL;
641#endif
642#endif
643}
644
645GDir::~GDir() {
646  delete path;
647#if defined(WIN32)
648  if (hnd) {
649    FindClose(hnd);
650    hnd = NULL;
651  }
652#elif defined(ACORN)
653#elif defined(MACOS)
654#else
655  if (dir)
656    closedir(dir);
657#endif
658}
659
660GDirEntry *GDir::getNextEntry() {
661  GDirEntry *e;
662
663#if defined(WIN32)
664  if (hnd) {
665    e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
666    if (hnd  && !FindNextFile(hnd, &ffd)) {
667      FindClose(hnd);
668      hnd = NULL;
669    }
670  } else {
671    e = NULL;
672  }
673#elif defined(ACORN)
674#elif defined(MACOS)
675#elif defined(VMS)
676  struct dirent *ent;
677  e = NULL;
678  if (dir) {
679    if (needParent) {
680      e = new GDirEntry(path->getCString(), "-", doStat);
681      needParent = gFalse;
682      return e;
683    }
684    ent = readdir(dir);
685    if (ent) {
686      e = new GDirEntry(path->getCString(), ent->d_name, doStat);
687    }
688  }
689#else
690  struct dirent *ent;
691  e = NULL;
692  if (dir) {
693    ent = readdir(dir);
694    if (ent && !strcmp(ent->d_name, ".")) {
695      ent = readdir(dir);
696    }
697    if (ent) {
698      e = new GDirEntry(path->getCString(), ent->d_name, doStat);
699    }
700  }
701#endif
702
703  return e;
704}
705
706void GDir::rewind() {
707#ifdef WIN32
708  GooString *tmp;
709
710  if (hnd)
711    FindClose(hnd);
712  tmp = path->copy();
713  tmp->append("/*.*");
714  hnd = FindFirstFile(tmp->getCString(), &ffd);
715  delete tmp;
716#elif defined(ACORN)
717#elif defined(MACOS)
718#else
719  if (dir)
720    rewinddir(dir);
721#ifdef VMS
722  needParent = strchr(path->getCString(), '[') != NULL;
723#endif
724#endif
725}
Note: See TracBrowser for help on using the repository browser.