filters

gfile.cc

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