Back to index

tetex-bin  3.0
gfile.cc
Go to the documentation of this file.
00001 //========================================================================
00002 //
00003 // gfile.cc
00004 //
00005 // Miscellaneous file and directory name manipulation.
00006 //
00007 // Copyright 1996-2003 Glyph & Cog, LLC
00008 //
00009 //========================================================================
00010 
00011 #include <aconf.h>
00012 
00013 #ifndef WIN32
00014 #  if defined(MACOS)
00015 #    include <sys/stat.h>
00016 #  elif !defined(ACORN)
00017 #    include <sys/types.h>
00018 #    include <sys/stat.h>
00019 #    include <fcntl.h>
00020 #  endif
00021 #  include <limits.h>
00022 #  include <string.h>
00023 #  if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
00024 #    include <pwd.h>
00025 #  endif
00026 #  if defined(VMS) && (__DECCXX_VER < 50200000)
00027 #    include <unixlib.h>
00028 #  endif
00029 #endif // WIN32
00030 #include "GString.h"
00031 #include "gfile.h"
00032 
00033 // Some systems don't define this, so just make it something reasonably
00034 // large.
00035 #ifndef PATH_MAX
00036 #define PATH_MAX 1024
00037 #endif
00038 
00039 //------------------------------------------------------------------------
00040 
00041 GString *getHomeDir() {
00042 #ifdef VMS
00043   //---------- VMS ----------
00044   return new GString("SYS$LOGIN:");
00045 
00046 #elif defined(__EMX__) || defined(WIN32)
00047   //---------- OS/2+EMX and Win32 ----------
00048   char *s;
00049   GString *ret;
00050 
00051   if ((s = getenv("HOME")))
00052     ret = new GString(s);
00053   else
00054     ret = new GString(".");
00055   return ret;
00056 
00057 #elif defined(ACORN)
00058   //---------- RISCOS ----------
00059   return new GString("@");
00060 
00061 #elif defined(MACOS)
00062   //---------- MacOS ----------
00063   return new GString(":");
00064 
00065 #else
00066   //---------- Unix ----------
00067   char *s;
00068   struct passwd *pw;
00069   GString *ret;
00070 
00071   if ((s = getenv("HOME"))) {
00072     ret = new GString(s);
00073   } else {
00074     if ((s = getenv("USER")))
00075       pw = getpwnam(s);
00076     else
00077       pw = getpwuid(getuid());
00078     if (pw)
00079       ret = new GString(pw->pw_dir);
00080     else
00081       ret = new GString(".");
00082   }
00083   return ret;
00084 #endif
00085 }
00086 
00087 GString *getCurrentDir() {
00088   char buf[PATH_MAX+1];
00089 
00090 #if defined(__EMX__)
00091   if (_getcwd2(buf, sizeof(buf)))
00092 #elif defined(WIN32)
00093   if (GetCurrentDirectory(sizeof(buf), buf))
00094 #elif defined(ACORN)
00095   if (strcpy(buf, "@"))
00096 #elif defined(MACOS)
00097   if (strcpy(buf, ":"))
00098 #else
00099   if (getcwd(buf, sizeof(buf)))
00100 #endif
00101     return new GString(buf);
00102   return new GString();
00103 }
00104 
00105 GString *appendToPath(GString *path, char *fileName) {
00106 #if defined(VMS)
00107   //---------- VMS ----------
00108   //~ this should handle everything necessary for file
00109   //~ requesters, but it's certainly not complete
00110   char *p0, *p1, *p2;
00111   char *q1;
00112 
00113   p0 = path->getCString();
00114   p1 = p0 + path->getLength() - 1;
00115   if (!strcmp(fileName, "-")) {
00116     if (*p1 == ']') {
00117       for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
00118       if (*p2 == '[')
00119        ++p2;
00120       path->del(p2 - p0, p1 - p2);
00121     } else if (*p1 == ':') {
00122       path->append("[-]");
00123     } else {
00124       path->clear();
00125       path->append("[-]");
00126     }
00127   } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
00128     if (*p1 == ']') {
00129       path->insert(p1 - p0, '.');
00130       path->insert(p1 - p0 + 1, fileName, q1 - fileName);
00131     } else if (*p1 == ':') {
00132       path->append('[');
00133       path->append(']');
00134       path->append(fileName, q1 - fileName);
00135     } else {
00136       path->clear();
00137       path->append(fileName, q1 - fileName);
00138     }
00139   } else {
00140     if (*p1 != ']' && *p1 != ':')
00141       path->clear();
00142     path->append(fileName);
00143   }
00144   return path;
00145 
00146 #elif defined(WIN32)
00147   //---------- Win32 ----------
00148   GString *tmp;
00149   char buf[256];
00150   char *fp;
00151 
00152   tmp = new GString(path);
00153   tmp->append('/');
00154   tmp->append(fileName);
00155   GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
00156   delete tmp;
00157   path->clear();
00158   path->append(buf);
00159   return path;
00160 
00161 #elif defined(ACORN)
00162   //---------- RISCOS ----------
00163   char *p;
00164   int i;
00165 
00166   path->append(".");
00167   i = path->getLength();
00168   path->append(fileName);
00169   for (p = path->getCString() + i; *p; ++p) {
00170     if (*p == '/') {
00171       *p = '.';
00172     } else if (*p == '.') {
00173       *p = '/';
00174     }
00175   }
00176   return path;
00177 
00178 #elif defined(MACOS)
00179   //---------- MacOS ----------
00180   char *p;
00181   int i;
00182 
00183   path->append(":");
00184   i = path->getLength();
00185   path->append(fileName);
00186   for (p = path->getCString() + i; *p; ++p) {
00187     if (*p == '/') {
00188       *p = ':';
00189     } else if (*p == '.') {
00190       *p = ':';
00191     }
00192   }
00193   return path;
00194 
00195 #elif defined(__EMX__)
00196   //---------- OS/2+EMX ----------
00197   int i;
00198 
00199   // appending "." does nothing
00200   if (!strcmp(fileName, "."))
00201     return path;
00202 
00203   // appending ".." goes up one directory
00204   if (!strcmp(fileName, "..")) {
00205     for (i = path->getLength() - 2; i >= 0; --i) {
00206       if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
00207          path->getChar(i) == ':')
00208        break;
00209     }
00210     if (i <= 0) {
00211       if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
00212        path->del(1, path->getLength() - 1);
00213       } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
00214        path->del(2, path->getLength() - 2);
00215       } else {
00216        path->clear();
00217        path->append("..");
00218       }
00219     } else {
00220       if (path->getChar(i-1) == ':')
00221        ++i;
00222       path->del(i, path->getLength() - i);
00223     }
00224     return path;
00225   }
00226 
00227   // otherwise, append "/" and new path component
00228   if (path->getLength() > 0 &&
00229       path->getChar(path->getLength() - 1) != '/' &&
00230       path->getChar(path->getLength() - 1) != '\\')
00231     path->append('/');
00232   path->append(fileName);
00233   return path;
00234 
00235 #else
00236   //---------- Unix ----------
00237   int i;
00238 
00239   // appending "." does nothing
00240   if (!strcmp(fileName, "."))
00241     return path;
00242 
00243   // appending ".." goes up one directory
00244   if (!strcmp(fileName, "..")) {
00245     for (i = path->getLength() - 2; i >= 0; --i) {
00246       if (path->getChar(i) == '/')
00247        break;
00248     }
00249     if (i <= 0) {
00250       if (path->getChar(0) == '/') {
00251        path->del(1, path->getLength() - 1);
00252       } else {
00253        path->clear();
00254        path->append("..");
00255       }
00256     } else {
00257       path->del(i, path->getLength() - i);
00258     }
00259     return path;
00260   }
00261 
00262   // otherwise, append "/" and new path component
00263   if (path->getLength() > 0 &&
00264       path->getChar(path->getLength() - 1) != '/')
00265     path->append('/');
00266   path->append(fileName);
00267   return path;
00268 #endif
00269 }
00270 
00271 GString *grabPath(char *fileName) {
00272 #ifdef VMS
00273   //---------- VMS ----------
00274   char *p;
00275 
00276   if ((p = strrchr(fileName, ']')))
00277     return new GString(fileName, p + 1 - fileName);
00278   if ((p = strrchr(fileName, ':')))
00279     return new GString(fileName, p + 1 - fileName);
00280   return new GString();
00281 
00282 #elif defined(__EMX__) || defined(WIN32)
00283   //---------- OS/2+EMX and Win32 ----------
00284   char *p;
00285 
00286   if ((p = strrchr(fileName, '/')))
00287     return new GString(fileName, p - fileName);
00288   if ((p = strrchr(fileName, '\\')))
00289     return new GString(fileName, p - fileName);
00290   if ((p = strrchr(fileName, ':')))
00291     return new GString(fileName, p + 1 - fileName);
00292   return new GString();
00293 
00294 #elif defined(ACORN)
00295   //---------- RISCOS ----------
00296   char *p;
00297 
00298   if ((p = strrchr(fileName, '.')))
00299     return new GString(fileName, p - fileName);
00300   return new GString();
00301 
00302 #elif defined(MACOS)
00303   //---------- MacOS ----------
00304   char *p;
00305 
00306   if ((p = strrchr(fileName, ':')))
00307     return new GString(fileName, p - fileName);
00308   return new GString();
00309 
00310 #else
00311   //---------- Unix ----------
00312   char *p;
00313 
00314   if ((p = strrchr(fileName, '/')))
00315     return new GString(fileName, p - fileName);
00316   return new GString();
00317 #endif
00318 }
00319 
00320 GBool isAbsolutePath(char *path) {
00321 #ifdef VMS
00322   //---------- VMS ----------
00323   return strchr(path, ':') ||
00324         (path[0] == '[' && path[1] != '.' && path[1] != '-');
00325 
00326 #elif defined(__EMX__) || defined(WIN32)
00327   //---------- OS/2+EMX and Win32 ----------
00328   return path[0] == '/' || path[0] == '\\' || path[1] == ':';
00329 
00330 #elif defined(ACORN)
00331   //---------- RISCOS ----------
00332   return path[0] == '$';
00333 
00334 #elif defined(MACOS)
00335   //---------- MacOS ----------
00336   return path[0] != ':';
00337 
00338 #else
00339   //---------- Unix ----------
00340   return path[0] == '/';
00341 #endif
00342 }
00343 
00344 GString *makePathAbsolute(GString *path) {
00345 #ifdef VMS
00346   //---------- VMS ----------
00347   char buf[PATH_MAX+1];
00348 
00349   if (!isAbsolutePath(path->getCString())) {
00350     if (getcwd(buf, sizeof(buf))) {
00351       path->insert(0, buf);
00352     }
00353   }
00354   return path;
00355 
00356 #elif defined(WIN32)
00357   //---------- Win32 ----------
00358   char buf[_MAX_PATH];
00359   char *fp;
00360 
00361   buf[0] = '\0';
00362   if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
00363     path->clear();
00364     return path;
00365   }
00366   path->clear();
00367   path->append(buf);
00368   return path;
00369 
00370 #elif defined(ACORN)
00371   //---------- RISCOS ----------
00372   path->insert(0, '@');
00373   return path;
00374 
00375 #elif defined(MACOS)
00376   //---------- MacOS ----------
00377   path->del(0, 1);
00378   return path;
00379 
00380 #else
00381   //---------- Unix and OS/2+EMX ----------
00382   struct passwd *pw;
00383   char buf[PATH_MAX+1];
00384   GString *s;
00385   char *p1, *p2;
00386   int n;
00387 
00388   if (path->getChar(0) == '~') {
00389     if (path->getChar(1) == '/' ||
00390 #ifdef __EMX__
00391        path->getChar(1) == '\\' ||
00392 #endif
00393        path->getLength() == 1) {
00394       path->del(0, 1);
00395       s = getHomeDir();
00396       path->insert(0, s);
00397       delete s;
00398     } else {
00399       p1 = path->getCString() + 1;
00400 #ifdef __EMX__
00401       for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
00402 #else
00403       for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
00404 #endif
00405       if ((n = p2 - p1) > PATH_MAX)
00406        n = PATH_MAX;
00407       strncpy(buf, p1, n);
00408       buf[n] = '\0';
00409       if ((pw = getpwnam(buf))) {
00410        path->del(0, p2 - p1 + 1);
00411        path->insert(0, pw->pw_dir);
00412       }
00413     }
00414   } else if (!isAbsolutePath(path->getCString())) {
00415     if (getcwd(buf, sizeof(buf))) {
00416 #ifndef __EMX__
00417       path->insert(0, '/');
00418 #endif
00419       path->insert(0, buf);
00420     }
00421   }
00422   return path;
00423 #endif
00424 }
00425 
00426 time_t getModTime(char *fileName) {
00427 #ifdef WIN32
00428   //~ should implement this, but it's (currently) only used in xpdf
00429   return 0;
00430 #else
00431   struct stat statBuf;
00432 
00433   if (stat(fileName, &statBuf)) {
00434     return 0;
00435   }
00436   return statBuf.st_mtime;
00437 #endif
00438 }
00439 
00440 GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
00441 #if defined(WIN32)
00442   //---------- Win32 ----------
00443   char *s;
00444 
00445   if (!(s = _tempnam(getenv("TEMP"), NULL))) {
00446     return gFalse;
00447   }
00448   *name = new GString(s);
00449   free(s);
00450   if (ext) {
00451     (*name)->append(ext);
00452   }
00453   if (!(*f = fopen((*name)->getCString(), mode))) {
00454     delete (*name);
00455     return gFalse;
00456   }
00457   return gTrue;
00458 #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
00459   //---------- non-Unix ----------
00460   char *s;
00461 
00462   // There is a security hole here: an attacker can create a symlink
00463   // with this file name after the tmpnam call and before the fopen
00464   // call.  I will happily accept fixes to this function for non-Unix
00465   // OSs.
00466   if (!(s = tmpnam(NULL))) {
00467     return gFalse;
00468   }
00469   *name = new GString(s);
00470   if (ext) {
00471     (*name)->append(ext);
00472   }
00473   if (!(*f = fopen((*name)->getCString(), mode))) {
00474     delete (*name);
00475     return gFalse;
00476   }
00477   return gTrue;
00478 #else
00479   //---------- Unix ----------
00480   char *s;
00481   int fd;
00482 
00483   if (ext) {
00484 #if HAVE_MKSTEMPS
00485     if ((s = getenv("TMPDIR"))) {
00486       *name = new GString(s);
00487     } else {
00488       *name = new GString("/tmp");
00489     }
00490     (*name)->append("/XXXXXX")->append(ext);
00491     fd = mkstemps((*name)->getCString(), strlen(ext));
00492 #else
00493     if (!(s = tmpnam(NULL))) {
00494       return gFalse;
00495     }
00496     *name = new GString(s);
00497     (*name)->append(ext);
00498     fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
00499 #endif
00500   } else {
00501 #if HAVE_MKSTEMP
00502     if ((s = getenv("TMPDIR"))) {
00503       *name = new GString(s);
00504     } else {
00505       *name = new GString("/tmp");
00506     }
00507     (*name)->append("/XXXXXX");
00508     fd = mkstemp((*name)->getCString());
00509 #else // HAVE_MKSTEMP
00510     if (!(s = tmpnam(NULL))) {
00511       return gFalse;
00512     }
00513     *name = new GString(s);
00514     fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
00515 #endif // HAVE_MKSTEMP
00516   }
00517   if (fd < 0 || !(*f = fdopen(fd, mode))) {
00518     delete *name;
00519     return gFalse;
00520   }
00521   return gTrue;
00522 #endif
00523 }
00524 
00525 GBool executeCommand(char *cmd) {
00526 #ifdef VMS
00527   return system(cmd) ? gTrue : gFalse;
00528 #else
00529   return system(cmd) ? gFalse : gTrue;
00530 #endif
00531 }
00532 
00533 char *getLine(char *buf, int size, FILE *f) {
00534   int c, i;
00535 
00536   i = 0;
00537   while (i < size - 1) {
00538     if ((c = fgetc(f)) == EOF) {
00539       break;
00540     }
00541     buf[i++] = (char)c;
00542     if (c == '\x0a') {
00543       break;
00544     }
00545     if (c == '\x0d') {
00546       c = fgetc(f);
00547       if (c == '\x0a' && i < size - 1) {
00548        buf[i++] = (char)c;
00549       } else if (c != EOF) {
00550        ungetc(c, f);
00551       }
00552       break;
00553     }
00554   }
00555   buf[i] = '\0';
00556   if (i == 0) {
00557     return NULL;
00558   }
00559   return buf;
00560 }
00561 
00562 //------------------------------------------------------------------------
00563 // GDir and GDirEntry
00564 //------------------------------------------------------------------------
00565 
00566 GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
00567 #ifdef VMS
00568   char *p;
00569 #elif defined(WIN32)
00570   int fa;
00571   GString *s;
00572 #elif defined(ACORN)
00573 #else
00574   struct stat st;
00575   GString *s;
00576 #endif
00577 
00578   name = new GString(nameA);
00579   dir = gFalse;
00580   if (doStat) {
00581 #ifdef VMS
00582     if (!strcmp(nameA, "-") ||
00583        ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
00584       dir = gTrue;
00585 #elif defined(ACORN)
00586 #else
00587     s = new GString(dirPath);
00588     appendToPath(s, nameA);
00589 #ifdef WIN32
00590     fa = GetFileAttributes(s->getCString());
00591     dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
00592 #else
00593     if (stat(s->getCString(), &st) == 0)
00594       dir = S_ISDIR(st.st_mode);
00595 #endif
00596     delete s;
00597 #endif
00598   }
00599 }
00600 
00601 GDirEntry::~GDirEntry() {
00602   delete name;
00603 }
00604 
00605 GDir::GDir(char *name, GBool doStatA) {
00606   path = new GString(name);
00607   doStat = doStatA;
00608 #if defined(WIN32)
00609   GString *tmp;
00610 
00611   tmp = path->copy();
00612   tmp->append("/*.*");
00613   hnd = FindFirstFile(tmp->getCString(), &ffd);
00614   delete tmp;
00615 #elif defined(ACORN)
00616 #elif defined(MACOS)
00617 #else
00618   dir = opendir(name);
00619 #ifdef VMS
00620   needParent = strchr(name, '[') != NULL;
00621 #endif
00622 #endif
00623 }
00624 
00625 GDir::~GDir() {
00626   delete path;
00627 #if defined(WIN32)
00628   if (hnd) {
00629     FindClose(hnd);
00630     hnd = NULL;
00631   }
00632 #elif defined(ACORN)
00633 #elif defined(MACOS)
00634 #else
00635   if (dir)
00636     closedir(dir);
00637 #endif
00638 }
00639 
00640 GDirEntry *GDir::getNextEntry() {
00641   GDirEntry *e;
00642 
00643 #if defined(WIN32)
00644   if (hnd) {
00645     e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
00646     if (hnd  && !FindNextFile(hnd, &ffd)) {
00647       FindClose(hnd);
00648       hnd = NULL;
00649     }
00650   } else {
00651     e = NULL;
00652   }
00653 #elif defined(ACORN)
00654 #elif defined(MACOS)
00655 #elif defined(VMS)
00656   struct dirent *ent;
00657   e = NULL;
00658   if (dir) {
00659     if (needParent) {
00660       e = new GDirEntry(path->getCString(), "-", doStat);
00661       needParent = gFalse;
00662       return e;
00663     }
00664     ent = readdir(dir);
00665     if (ent) {
00666       e = new GDirEntry(path->getCString(), ent->d_name, doStat);
00667     }
00668   }
00669 #else
00670   struct dirent *ent;
00671   e = NULL;
00672   if (dir) {
00673     ent = readdir(dir);
00674     if (ent && !strcmp(ent->d_name, ".")) {
00675       ent = readdir(dir);
00676     }
00677     if (ent) {
00678       e = new GDirEntry(path->getCString(), ent->d_name, doStat);
00679     }
00680   }
00681 #endif
00682 
00683   return e;
00684 }
00685 
00686 void GDir::rewind() {
00687 #ifdef WIN32
00688   GString *tmp;
00689 
00690   if (hnd)
00691     FindClose(hnd);
00692   tmp = path->copy();
00693   tmp->append("/*.*");
00694   hnd = FindFirstFile(tmp->getCString(), &ffd);
00695   delete tmp;
00696 #elif defined(ACORN)
00697 #elif defined(MACOS)
00698 #else
00699   if (dir)
00700     rewinddir(dir);
00701 #ifdef VMS
00702   needParent = strchr(path->getCString(), '[') != NULL;
00703 #endif
00704 #endif
00705 }