From 67a2f24b86e3ecdb2354af727962f67ebc7bcd7e Mon Sep 17 00:00:00 2001 From: "mcmullen%netscape.com" Date: Wed, 6 Jan 1999 23:38:21 +0000 Subject: [PATCH] Added a directory iterator class. Added canonification and recursive directory creation, and some other handy methods. Eventual goal: replace xp_file.h entirely. git-svn-id: svn://10.0.0.236/trunk@17274 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/base/public/nsFileSpec.h | 120 ++++++- mozilla/base/src/mac/nsFileSpecMac.cpp | 292 ++++++++++++++-- mozilla/base/src/nsFileSpec.cpp | 386 +++++++++++++-------- mozilla/base/src/unix/nsFileSpecUnix.cpp | 188 +++++++++- mozilla/base/src/windows/nsFileSpecWin.cpp | 159 ++++++++- mozilla/base/tests/FilesTest.cpp | 142 +++++++- mozilla/xpcom/io/nsFileSpec.cpp | 386 +++++++++++++-------- mozilla/xpcom/io/nsFileSpec.h | 120 ++++++- mozilla/xpcom/io/nsFileSpecMac.cpp | 292 ++++++++++++++-- mozilla/xpcom/io/nsFileSpecUnix.cpp | 188 +++++++++- mozilla/xpcom/io/nsFileSpecWin.cpp | 159 ++++++++- mozilla/xpcom/tests/FilesTest.cpp | 142 +++++++- 12 files changed, 2162 insertions(+), 412 deletions(-) diff --git a/mozilla/base/public/nsFileSpec.h b/mozilla/base/public/nsFileSpec.h index 1c73419c631..b27dcc6b85f 100644 --- a/mozilla/base/public/nsFileSpec.h +++ b/mozilla/base/public/nsFileSpec.h @@ -127,6 +127,10 @@ #ifdef XP_MAC #include +#elif defined(XP_UNIX) || defined (XP_OS2) +#include +#elif 0 // defined(XP_PC) +#include "winfile.h" #endif //======================================================================================== @@ -150,7 +154,7 @@ class NS_BASE nsNativeFileSpec { public: nsNativeFileSpec(); - explicit nsNativeFileSpec(const char* inString); + explicit nsNativeFileSpec(const char* inString, bool inCreateDirs = false); explicit nsNativeFileSpec(const nsFilePath& inPath); explicit nsNativeFileSpec(const nsFileURL& inURL); nsNativeFileSpec(const nsNativeFileSpec& inPath); @@ -177,12 +181,12 @@ class NS_BASE nsNativeFileSpec operator const FSSpec& () const { return mSpec; } OSErr Error() const { return mError; } void MakeAliasSafe(); - // Called for the spec of an alias. Copies the alias to - // a secret temp directory and modifies the spec to point - // to it. Sets mError. + // Called for the spec of an alias. Copies the alias to + // a secret temp directory and modifies the spec to point + // to it. Sets mError. void ResolveAlias(bool& wasAliased); - // Called for the spec of an alias. Modifies the spec to - // point to the original. Sets mError. + // Called for the spec of an alias. Modifies the spec to + // point to the original. Sets mError. void MakeUnique(ConstStr255Param inSuggestedLeafName); StringPtr GetLeafPName() { return mSpec.name; } ConstStr255Param GetLeafPName() const { return mSpec.name; } @@ -194,14 +198,58 @@ class NS_BASE nsNativeFileSpec bool Valid() const { return true; } // Fixme. #endif // XP_MAC - friend NS_BASE nsOutputFileStream& operator << (nsOutputFileStream& s, const nsNativeFileSpec& spec); + friend NS_BASE nsOutputFileStream& operator << ( + nsOutputFileStream& s, + const nsNativeFileSpec& spec); + + //-------------------------------------------------- + // Queries and path algebra. These do not modify the disk. + //-------------------------------------------------- char* GetLeafName() const; // Allocated. Use delete []. void SetLeafName(const char* inLeafName); - bool Exists() const; + // inLeafName can be a relative path, so this allows + // one kind of concatenation of "paths". + + void GetParent(nsNativeFileSpec& outSpec) const; + // Return the filespec of the parent directory. Used + // in conjunction with GetLeafName(), this lets you + // parse a path into a list of node names. Beware, + // however, that the top node is still not a name, + // but a spec. Volumes on Macintosh can have identical + // names. Perhaps could be used for an operator --() ? + + nsNativeFileSpec operator + (const char* inRelativePath) const; + void operator += (const char* inRelativePath); + // Concatenate the relative path to this directory. + // Used for constructing the filespec of a descendant. + // This must be a directory for this to work. This differs + // from SetLeafName(), since the latter will work + // starting with a sibling of the directory and throws + // away its leaf information, whereas this one assumes + // this is a directory, and the relative path starts + // "below" this. + void MakeUnique(); void MakeUnique(const char* inSuggestedLeafName); + bool IsDirectory() const; + // More stringent than Exists() + bool IsFile() const; + // More stringent than Exists() + bool Exists() const; + + //-------------------------------------------------- + // Creation and deletion of objects. These can modify the disk. + //-------------------------------------------------- + + void CreateDirectory(int mode = 0700 /* for unix */); + void Delete(bool inRecursive); + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + private: friend class nsFilePath; #ifdef XP_MAC @@ -221,7 +269,7 @@ class NS_BASE nsFileURL { public: nsFileURL(const nsFileURL& inURL); - explicit nsFileURL(const char* inString); + explicit nsFileURL(const char* inString, bool inCreateDirs = false); explicit nsFileURL(const nsFilePath& inPath); explicit nsFileURL(const nsNativeFileSpec& inPath); virtual ~nsFileURL(); @@ -247,7 +295,7 @@ class NS_BASE nsFileURL operator char* (); operator const char* const (); private: - friend class nsFilePath; // to allow construction of nsFilePath + friend class nsFilePath; // to allow construction of nsFilePath char* mURL; #ifdef XP_MAC // Since the path on the macintosh does not uniquely specify a file (volumes @@ -264,7 +312,7 @@ class NS_BASE nsFilePath { public: nsFilePath(const nsFilePath& inPath); - explicit nsFilePath(const char* inString); + explicit nsFilePath(const char* inString, bool inCreateDirs = false); explicit nsFilePath(const nsFileURL& inURL); explicit nsFilePath(const nsNativeFileSpec& inPath); virtual ~nsFilePath(); @@ -292,7 +340,7 @@ class NS_BASE nsFilePath private: - char* mPath; + char* mPath; #ifdef XP_MAC // Since the path on the macintosh does not uniquely specify a file (volumes // can have the same name), stash the secret nsNativeFileSpec, too. @@ -300,4 +348,52 @@ class NS_BASE nsFilePath #endif }; // class nsFilePath +//======================================================================================== +class nsDirectoryIterator +// Example: +// +// nsNativeFileSpec parentDir(...); // directory over whose children we shall iterate +// for (nsDirectoryIterator i(parentDir); i; i++) +// { +// // do something with (const nsNativeFileSpec&)i +// } +// +// or: +// +// for (nsDirectoryIterator i(parentDir, false); i; i--) +// { +// // do something with (const nsNativeFileSpec&)i +// } +// +// Currently, the only platform on which backwards iteration actually goes backwards +// is Macintosh. On other platforms, both styles will work, but will go forwards. +//======================================================================================== +{ + public: + nsDirectoryIterator( + const nsNativeFileSpec& parent, + int iterateDirection = +1); +#ifndef XP_MAC + // Macintosh currently doesn't allocate, so needn't clean up. + virtual ~nsDirectoryIterator(); +#endif + operator bool() const { return mExists; } + nsDirectoryIterator& operator ++(); // moves to the next item, if any. + nsDirectoryIterator& operator ++(int) { return ++(*this); } // post-increment. + nsDirectoryIterator& operator --(); // moves to the previous item, if any. + nsDirectoryIterator& operator --(int) { return --(*this); } // post-decrement. + operator nsNativeFileSpec&() { return mCurrent; } + private: + nsNativeFileSpec mCurrent; + bool mExists; + +#if defined(XP_UNIX) // || defined(XP_PC) add when ready + DIR* mDir; +#elif defined(XP_MAC) + OSErr SetToIndex(); + short mIndex; + short mMaxIndex; +#endif +}; // class nsDirectoryIterator + #endif // _FILESPEC_H_ diff --git a/mozilla/base/src/mac/nsFileSpecMac.cpp b/mozilla/base/src/mac/nsFileSpecMac.cpp index d8bd5f45b27..d92624bd669 100644 --- a/mozilla/base/src/mac/nsFileSpecMac.cpp +++ b/mozilla/base/src/mac/nsFileSpecMac.cpp @@ -21,6 +21,7 @@ #include "FullPath.h" #include "FileCopy.h" +#include "MoreFilesExtras.h" #include "nsEscape.h" #include @@ -39,14 +40,16 @@ namespace MacFileHelpers memcpy(dst, src, 1 + src[0]); } - void PLstrcpy(Str255 dst, const char* src, int inMaxLen); + void PLstrcpy(Str255 dst, const char* src, int inMaxLen=255); + void PLstrncpy(Str255 dst, const char* src, int inMaxLen); void SwapSlashColon(char * s); OSErr FSSpecFromFullUnixPath( const char * unixPath, FSSpec& outSpec, Boolean resolveAlias, - Boolean allowPartial = false); + Boolean allowPartial = false, + Boolean createDirs = false); char* MacPathFromUnixPath(const char* unixPath); char* EncodeMacPath( char* inPath, // NOT const - gets clobbered @@ -54,7 +57,8 @@ namespace MacFileHelpers Boolean doEscape ); OSErr FSSpecFromPathname( const char* inPathNamePtr, - FSSpec& outSpec); + FSSpec& outSpec, + Boolean inCreateDirs); char* PathNameFromFSSpec( const FSSpec& inSpec, Boolean wantLeafName ); @@ -81,7 +85,7 @@ namespace MacFileHelpers //---------------------------------------------------------------------------------------- void MacFileHelpers::PLstrcpy(Str255 dst, const char* src, int inMax) -//======================================================================================== +//---------------------------------------------------------------------------------------- { int srcLength = strlen(src); NS_ASSERTION(srcLength <= inMax, "Oops, string is too long!"); @@ -91,6 +95,17 @@ void MacFileHelpers::PLstrcpy(Str255 dst, const char* src, int inMax) memcpy(&dst[1], src, srcLength); } +//---------------------------------------------------------------------------------------- +void MacFileHelpers::PLstrncpy(Str255 dst, const char* src, int inMax) +//---------------------------------------------------------------------------------------- +{ + int srcLength = strlen(src); + if (srcLength > inMax) + srcLength = inMax; + dst[0] = srcLength; + memcpy(&dst[1], src, srcLength); +} + //----------------------------------- void MacFileHelpers::SwapSlashColon(char * s) //----------------------------------- @@ -218,7 +233,10 @@ char* MacFileHelpers::MacPathFromUnixPath(const char* unixPath) } // MacFileHelpers::MacPathFromUnixPath //---------------------------------------------------------------------------------------- -OSErr MacFileHelpers::FSSpecFromPathname(const char* inPathNamePtr, FSSpec& outSpec) +OSErr MacFileHelpers::FSSpecFromPathname( + const char* inPathNamePtr, + FSSpec& outSpec, + Boolean inCreateDirs) // FSSpecFromPathname reverses PathNameFromFSSpec. // It returns a FSSpec given a c string which is a mac pathname. //---------------------------------------------------------------------------------------- @@ -226,22 +244,55 @@ OSErr MacFileHelpers::FSSpecFromPathname(const char* inPathNamePtr, FSSpec& outS OSErr err; // Simplify this routine to use FSMakeFSSpec if length < 255. Otherwise use the MoreFiles // routine FSpLocationFromFullPath, which allocates memory, to handle longer pathnames. - if (strlen(inPathNamePtr) < 255) + + size_t inLength = strlen(inPathNamePtr); + if (inLength < 255) { - Str255 path; - - int pos = 0; - while ( (path[++pos] = *inPathNamePtr++) != 0 ) - ; - path[0] = pos-1; // save the length of the string (pos is the next open spot) - - err = ::FSMakeFSSpec(0, 0, path, &outSpec); + Str255 ppath; + MacFileHelpers::PLstrcpy(ppath, inPathNamePtr); + err = ::FSMakeFSSpec(0, 0, ppath, &outSpec); } else - err = FSpLocationFromFullPath(strlen(inPathNamePtr), inPathNamePtr, &outSpec); + err = FSpLocationFromFullPath(inLength, inPathNamePtr, &outSpec); + if (err == dirNFErr && inCreateDirs) + { + const char* path = inPathNamePtr; + outSpec.vRefNum = 0; + outSpec.parID = 0; + do { + // Locate the colon that terminates the node. + // But if we've a partial path (starting with a colon), find the second one. + const char* nextColon = strchr(path + (*path == ':'), ':'); + // Well, if there are no more colons, point to the end of the string. + if (!nextColon) + nextColon = path + strlen(path); + + // Make a pascal string out of this node. Include initial + // and final colon, if any! + Str255 ppath; + MacFileHelpers::PLstrncpy(ppath, path, nextColon - path + 1); + + // Use this string as a relative path using the directory created + // on the previous round (or directory 0,0 on the first round). + err = ::FSMakeFSSpec(outSpec.vRefNum, outSpec.parID, ppath, &outSpec); + + // If this was the leaf node, then we are done. + if (!*nextColon) + break; + + // If we got "file not found", then + // we need to create a directory. + if (err == fnfErr && *nextColon) + err = FSpDirCreate(&outSpec, smCurrentScript, &outSpec.parID); + // For some reason, this usually returns fnfErr, even though it works. + if (err != noErr && err != fnfErr) + return err; + path = nextColon; // next round + } while (1); + } return err; -} +} // MacFileHelpers::FSSpecFromPathname //---------------------------------------------------------------------------------------- OSErr MacFileHelpers::CreateFolderInFolder( @@ -320,7 +371,8 @@ OSErr MacFileHelpers::FSSpecFromFullUnixPath( const char * unixPath, FSSpec& outSpec, Boolean resolveAlias, - Boolean allowPartial) + Boolean allowPartial, + Boolean createDirs) // File spec from URL. Reverses GetURLFromFileSpec // Its input is only the part of the URL // JRM 97/01/08 changed this so that if it's a partial path (doesn't start with '/'), @@ -338,7 +390,7 @@ OSErr MacFileHelpers::FSSpecFromFullUnixPath( { NS_ASSERTION(*unixPath == '/' /*full path*/, "Not a full Unix path!"); } - err = FSSpecFromPathname(macPath, outSpec); + err = FSSpecFromPathname(macPath, outSpec, createDirs); if (err == fnfErr) err = noErr; Boolean dummy; @@ -468,11 +520,12 @@ nsNativeFileSpec::nsNativeFileSpec(const nsNativeFileSpec& inSpec) } //---------------------------------------------------------------------------------------- -nsNativeFileSpec::nsNativeFileSpec(const char* inString) +nsNativeFileSpec::nsNativeFileSpec(const char* inString, bool inCreateDirs) //---------------------------------------------------------------------------------------- { - mError = MacFileHelpers::FSSpecFromFullUnixPath(inString, mSpec, true, true); - // allow a partial path + mError = MacFileHelpers::FSSpecFromFullUnixPath( + inString, mSpec, true, true, inCreateDirs); + // allow a partial path, create as necessary if (mError == fnfErr) mError = noErr; } // nsNativeFileSpec::nsNativeFileSpec @@ -537,9 +590,13 @@ bool nsNativeFileSpec::Exists() const //---------------------------------------------------------------------------------------- void nsNativeFileSpec::SetLeafName(const char* inLeafName) +// In leaf name can actually be a partial path... //---------------------------------------------------------------------------------------- { - MacFileHelpers::PLstrcpy(mSpec.name, inLeafName, nsFileSpecHelpers::kMaxFilenameLength); + // what about long relative paths? Hmm? + Str255 partialPath; + MacFileHelpers::PLstrcpy(partialPath, inLeafName); + mError = FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, partialPath, &mSpec); } // nsNativeFileSpec::SetLeafName //---------------------------------------------------------------------------------------- @@ -579,10 +636,86 @@ void nsNativeFileSpec::ResolveAlias(bool& wasAliased) wasAliased = (wasAliased2 != false); } // nsNativeFileSpec::ResolveAlias +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + long dirID; + Boolean isDirectory; + return (noErr == FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && !isDirectory); +} // nsNativeFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + long dirID; + Boolean isDirectory; + return (noErr == FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && isDirectory); +} // nsNativeFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::GetParent(nsNativeFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + if (mError == noErr) + outSpec.mError = FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, NULL, outSpec); +} // nsNativeFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + long dirID; + Boolean isDirectory; + mError = FSpGetDirectoryID(&mSpec, &dirID, &isDirectory); + if (mError == noErr && isDirectory) + { + mError = FSMakeFSSpec(mSpec.vRefNum, dirID, "\pG'day", *this); + if (mError == noErr) + SetLeafName(inRelativePath); + } +} // nsNativeFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::CreateDirectory(int /* unix mode */) +//---------------------------------------------------------------------------------------- +{ + long ignoredDirID; + FSpDirCreate(&mSpec, smCurrentScript, &ignoredDirID); +} // nsNativeFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::Delete(bool inRecursive) +//---------------------------------------------------------------------------------------- +{ + if (inRecursive) + { + // MoreFilesExtras + mError = DeleteDirectory( + mSpec.vRefNum, + mSpec.parID, + const_cast(mSpec.name)); + } + else + mError = FSpDelete(&mSpec); +} // nsNativeFileSpec::Delete + + //======================================================================================== // Macintosh nsFilePath implementation //======================================================================================== +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const char* inString, bool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mPath(nsnull) +, mNativeFileSpec(inString, inCreateDirs) +{ + // Make canonical and absolute. + char * path = MacFileHelpers::PathNameFromFSSpec( mNativeFileSpec, TRUE ); + mPath = MacFileHelpers::EncodeMacPath(path, true, true); +} //---------------------------------------------------------------------------------------- nsFilePath::nsFilePath(const nsNativeFileSpec& inSpec) //---------------------------------------------------------------------------------------- @@ -601,3 +734,118 @@ void nsFilePath::operator = (const nsNativeFileSpec& inSpec) mPath = MacFileHelpers::EncodeMacPath(path, true, true); mNativeFileSpec = inSpec; } // nsFilePath::operator = + +//======================================================================================== +// nsFileURL implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const char* inString, bool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mURL(nsnull) +, mNativeFileSpec(inString + kFileURLPrefixLength, inCreateDirs) +{ + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + // Make canonical and absolute. + char* path = MacFileHelpers::PathNameFromFSSpec( mNativeFileSpec, TRUE ); + char* escapedPath = MacFileHelpers::EncodeMacPath(path, true, true); + mURL = nsFileSpecHelpers::StringDup(kFileURLPrefix, kFileURLPrefixLength + strlen(escapedPath)); + strcat(mURL, escapedPath); + delete [] escapedPath; +} // nsFileURL::nsFileURL + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator( + const nsNativeFileSpec& inDirectory +, int inIterateDirection) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mExists(false) + , mIndex(-1) +{ + CInfoPBRec pb; + DirInfo* dipb = (DirInfo*)&pb; + // Sorry about this, there seems to be a bug in CWPro 4: + const FSSpec& inSpec = inDirectory.nsNativeFileSpec::operator const FSSpec&(); + Str255 outName; + MacFileHelpers::PLstrcpy(outName, inSpec.name); + pb.hFileInfo.ioNamePtr = outName; + pb.hFileInfo.ioVRefNum = inSpec.vRefNum; + pb.hFileInfo.ioDirID = inSpec.parID; + pb.hFileInfo.ioFDirIndex = 0; // use ioNamePtr and ioDirID + + OSErr err = PBGetCatInfoSync( &pb ); + + // test that we have got a directory back, not a file + if ( (err != noErr ) || !( dipb->ioFlAttrib & 0x0010 ) ) + return; + // Sorry about this, there seems to be a bug in CWPro 4: + FSSpec& currentSpec = mCurrent.nsNativeFileSpec::operator FSSpec&(); + currentSpec.vRefNum = inSpec.vRefNum; + currentSpec.parID = dipb->ioDrDirID; + mMaxIndex = pb.dirInfo.ioDrNmFls; + if (inIterateDirection > 0) + { + mIndex = 0; // ready to increment + ++(*this); // the pre-increment operator + } + else + { + mIndex = mMaxIndex + 1; // ready to decrement + --(*this); // the pre-decrement operator + } +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +OSErr nsDirectoryIterator::SetToIndex() +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec cipb; + DirInfo *dipb=(DirInfo *)&cipb; + Str255 objectName; + dipb->ioCompletion = NULL; + dipb->ioFDirIndex = mIndex; + // Sorry about this, there seems to be a bug in CWPro 4: + FSSpec& currentSpec = mCurrent.nsNativeFileSpec::operator FSSpec&(); + dipb->ioVRefNum = currentSpec.vRefNum; /* Might need to use vRefNum, not sure*/ + dipb->ioDrDirID = currentSpec.parID; + dipb->ioNamePtr = objectName; + OSErr err = PBGetCatInfoSync(&cipb); + if (err == noErr) + err = FSMakeFSSpec(currentSpec.vRefNum, currentSpec.parID, objectName, ¤tSpec); + mExists = err == noErr; + return err; +} // nsDirectoryIterator::SetToIndex() + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + mExists = false; + while (--mIndex > 0) + { + OSErr err = SetToIndex(); + if (err == noErr) + break; + } + return *this; +} // nsDirectoryIterator::operator -- + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = false; + if (mIndex >= 0) // probably trying to use a file as a directory! + while (++mIndex <= mMaxIndex) + { + OSErr err = SetToIndex(); + if (err == noErr) + break; + } + return *this; +} // nsDirectoryIterator::operator ++ diff --git a/mozilla/base/src/nsFileSpec.cpp b/mozilla/base/src/nsFileSpec.cpp index df710c9a814..7a6403eea15 100644 --- a/mozilla/base/src/nsFileSpec.cpp +++ b/mozilla/base/src/nsFileSpec.cpp @@ -30,115 +30,180 @@ NS_NAMESPACE nsFileSpecHelpers //======================================================================================== { - enum - { kMaxFilenameLength = 31 // should work on Macintosh, Unix, and Win32. - , kMaxAltDigitLength = 5 - , kMaxCoreLeafNameLength = (kMaxFilenameLength - (kMaxAltDigitLength + 1)) - }; - NS_NAMESPACE_PROTOTYPE void LeafReplace( - char*& ioPath, - char inSeparator, - const char* inLeafName); - NS_NAMESPACE_PROTOTYPE char* GetLeaf(const char* inPath, char inSeparator); // allocated - NS_NAMESPACE_PROTOTYPE char* StringDup(const char* inString, int allocLength = 0); - NS_NAMESPACE_PROTOTYPE char* AllocCat(const char* inString1, const char* inString2); - NS_NAMESPACE_PROTOTYPE char* StringAssign(char*& ioString, const char* inOther); + enum + { kMaxFilenameLength = 31 // should work on Macintosh, Unix, and Win32. + , kMaxAltDigitLength = 5 + , kMaxCoreLeafNameLength = (kMaxFilenameLength - (kMaxAltDigitLength + 1)) + }; + NS_NAMESPACE_PROTOTYPE void LeafReplace( + char*& ioPath, + char inSeparator, + const char* inLeafName); +#ifndef XP_MAC + NS_NAMESPACE_PROTOTYPE void Canonify(char*& ioPath, bool inMakeDirs); + NS_NAMESPACE_PROTOTYPE void MakeAllDirectories(const char* inPath, int mode); +#endif + NS_NAMESPACE_PROTOTYPE char* GetLeaf(const char* inPath, char inSeparator); // allocated + NS_NAMESPACE_PROTOTYPE char* StringDup(const char* inString, int allocLength = 0); + NS_NAMESPACE_PROTOTYPE char* AllocCat(const char* inString1, const char* inString2); + NS_NAMESPACE_PROTOTYPE char* StringAssign(char*& ioString, const char* inOther); + NS_NAMESPACE_PROTOTYPE char* ReallocCat(char*& ioString, const char* inString1); } NS_NAMESPACE_END + //---------------------------------------------------------------------------------------- char* nsFileSpecHelpers::StringDup( - const char* inString, - int allocLength) + const char* inString, + int allocLength) //---------------------------------------------------------------------------------------- { - if (!allocLength && inString) - allocLength = strlen(inString); - char* newPath = inString || allocLength ? new char[allocLength + 1] : 0; - if (!newPath) - return NULL; - strcpy(newPath, inString); - return newPath; + if (!allocLength && inString) + allocLength = strlen(inString); + char* newPath = inString || allocLength ? new char[allocLength + 1] : nsnull; + if (!newPath) + return NULL; + strcpy(newPath, inString); + return newPath; } // nsFileSpecHelpers::StringDup //---------------------------------------------------------------------------------------- char* nsFileSpecHelpers::AllocCat( - const char* inString1, - const char* inString2) + const char* inString1, + const char* inString2) //---------------------------------------------------------------------------------------- { - if (!inString1) - return inString2 ? StringDup(inString2) : (char*)NULL; - if (!inString2) - return StringDup(inString1); - char* outString = StringDup(inString1, strlen(inString1) + strlen(inString2)); - if (outString) - strcat(outString, inString2); - return outString; + if (!inString1) + return inString2 ? StringDup(inString2) : (char*)NULL; + if (!inString2) + return StringDup(inString1); + char* outString = StringDup(inString1, strlen(inString1) + strlen(inString2)); + if (outString) + strcat(outString, inString2); + return outString; } // nsFileSpecHelpers::StringDup //---------------------------------------------------------------------------------------- char* nsFileSpecHelpers::StringAssign( - char*& ioString, - const char* inString2) + char*& ioString, + const char* inString2) //---------------------------------------------------------------------------------------- { - if (!inString2) - { - delete [] ioString; - ioString = (char*)NULL; - return ioString; - } - if (!ioString || (strlen(inString2) > strlen(ioString))) - { - delete [] ioString; - ioString = StringDup(inString2); - return ioString; - } - strcpy(ioString, inString2); - return ioString; + if (!inString2) + { + delete [] ioString; + ioString = (char*)NULL; + return ioString; + } + if (!ioString || (strlen(inString2) > strlen(ioString))) + { + delete [] ioString; + ioString = StringDup(inString2); + return ioString; + } + strcpy(ioString, inString2); + return ioString; } // nsFileSpecHelpers::StringAssign //---------------------------------------------------------------------------------------- void nsFileSpecHelpers::LeafReplace( - char*& ioPath, - char inSeparator, - const char* inLeafName) + char*& ioPath, + char inSeparator, + const char* inLeafName) //---------------------------------------------------------------------------------------- { - // Find the existing leaf name - if (!ioPath) - return; - if (!inLeafName) - { - *ioPath = '\0'; - return; - } - char* lastSeparator = strrchr(ioPath, inSeparator); - int oldLength = strlen(ioPath); - *(++lastSeparator) = '\0'; // strip the current leaf name - int newLength = lastSeparator - ioPath + strlen(inLeafName); - if (newLength > oldLength) - { - char* newPath = StringDup(ioPath, newLength + 1); - delete [] ioPath; - ioPath = newPath; - } - strcat(ioPath, inLeafName); -} // nsNativeFileSpec::SetLeafName + // Find the existing leaf name + if (!ioPath) + return; + if (!inLeafName) + { + *ioPath = '\0'; + return; + } + char* lastSeparator = strrchr(ioPath, inSeparator); + int oldLength = strlen(ioPath); + *(++lastSeparator) = '\0'; // strip the current leaf name + int newLength = lastSeparator - ioPath + strlen(inLeafName); + if (newLength > oldLength) + { + char* newPath = StringDup(ioPath, newLength + 1); + delete [] ioPath; + ioPath = newPath; + } + strcat(ioPath, inLeafName); +} // nsNativeFileSpec::LeafReplace //---------------------------------------------------------------------------------------- char* nsFileSpecHelpers::GetLeaf(const char* inPath, char inSeparator) // Returns a pointer to an allocated string representing the leaf. //---------------------------------------------------------------------------------------- { - if (!inPath) - return NULL; - char* lastSeparator = strrchr(inPath, inSeparator); - if (lastSeparator) - return StringDup(lastSeparator); - return StringDup(inPath); + if (!inPath) + return NULL; + char* lastSeparator = strrchr(inPath, inSeparator); + if (lastSeparator) + return StringDup(++lastSeparator); + return StringDup(inPath); } // nsNativeFileSpec::GetLeaf +#if defined(XP_UNIX) || defined(XP_PC) + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::MakeAllDirectories(const char* inPath, int mode) +// Make the path a valid one by creating all the intermediate directories. Does NOT +// make the leaf into a directory. This should be a unix path. +//---------------------------------------------------------------------------------------- +{ + if (!inPath) + return; + + char* pathCopy = nsFileSpecHelpers::StringDup( inPath ); + if (!pathCopy) + return; + + const char kSeparator = '/'; // I repeat: this should be a unix-style path. + const int kSkipFirst = 1; + +#ifdef XP_WIN + NS_ASSERTION( pathCopy[2] == '|', "No drive letter!" ); +#endif + char* currentStart = pathCopy; + char* currentEnd = strchr(currentStart + kSkipFirst, kSeparator); + if (currentEnd) + { + *currentEnd = '\0'; + nsNativeFileSpec spec(nsFilePath(pathCopy, false)); + do + { + // If the node doesn't exist, and it is not the initial node in a full path, + // then make a directory (We cannot make the initial (volume) node). + if (!spec.Exists() && *currentStart != kSeparator) + spec.CreateDirectory(mode); + if (!spec.Exists()) + { + NS_ASSERTION(spec.Exists(), "Could not create the directory?"); + break; + } + currentStart = ++currentEnd; + currentEnd = strchr(currentStart, kSeparator); + if (!currentEnd) + break; + spec += currentStart; // "lengthen" the path, adding the next node. + } while (currentEnd); + } + delete [] pathCopy; +} // nsFileSpecHelpers::MakeAllDirectories + +#endif // XP_PC || XP_UNIX + +//---------------------------------------------------------------------------------------- +char* nsFileSpecHelpers::ReallocCat(char*& ioString, const char* inString1) +//---------------------------------------------------------------------------------------- +{ + char* newString = AllocCat(ioString, inString1); + delete [] ioString; + ioString = newString; + return ioString; +} // nsNativeFileSpec::ReallocCat #if defined(XP_PC) #include "windows/nsFileSpecWin.cpp" // Windows-specific implementations @@ -149,26 +214,30 @@ char* nsFileSpecHelpers::GetLeaf(const char* inPath, char inSeparator) #endif //======================================================================================== -// nsFileURL implementation +// nsFileURL implementation //======================================================================================== +#ifndef XP_MAC //---------------------------------------------------------------------------------------- -nsFileURL::nsFileURL(const char* inString) +nsFileURL::nsFileURL(const char* inString, bool inCreateDirs) //---------------------------------------------------------------------------------------- -: mURL(nsFileSpecHelpers::StringDup(inString)) -#ifdef XP_MAC -, mNativeFileSpec(inString + kFileURLPrefixLength) -#endif +: mURL(nsnull) { - NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + if (!inString) + return; + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + // Make canonical and absolute. + nsFilePath path(inString + kFileURLPrefixLength, inCreateDirs); + *this = path; } // nsFileURL::nsFileURL +#endif //---------------------------------------------------------------------------------------- nsFileURL::nsFileURL(const nsFileURL& inOther) //---------------------------------------------------------------------------------------- -: mURL(nsFileSpecHelpers::StringDup(inOther.mURL)) +: mURL(nsFileSpecHelpers::StringDup(inOther.mURL)) #ifdef XP_MAC -, mNativeFileSpec(inOther.GetNativeSpec()) +, mNativeFileSpec(inOther.GetNativeSpec()) #endif { } // nsFileURL::nsFileURL @@ -176,18 +245,18 @@ nsFileURL::nsFileURL(const nsFileURL& inOther) //---------------------------------------------------------------------------------------- nsFileURL::nsFileURL(const nsFilePath& inOther) //---------------------------------------------------------------------------------------- -: mURL(nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)inOther)) +: mURL(nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)inOther)) #ifdef XP_MAC -, mNativeFileSpec(inOther.GetNativeSpec()) +, mNativeFileSpec(inOther.GetNativeSpec()) #endif { } // nsFileURL::nsFileURL //---------------------------------------------------------------------------------------- nsFileURL::nsFileURL(const nsNativeFileSpec& inOther) -: mURL(nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)nsFilePath(inOther))) +: mURL(nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)nsFilePath(inOther))) #ifdef XP_MAC -, mNativeFileSpec(inOther) +, mNativeFileSpec(inOther) #endif //---------------------------------------------------------------------------------------- { @@ -197,17 +266,17 @@ nsFileURL::nsFileURL(const nsNativeFileSpec& inOther) nsFileURL::~nsFileURL() //---------------------------------------------------------------------------------------- { - delete [] mURL; + delete [] mURL; } //---------------------------------------------------------------------------------------- void nsFileURL::operator = (const char* inString) //---------------------------------------------------------------------------------------- { - nsFileSpecHelpers::StringAssign(mURL, inString); - NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + nsFileSpecHelpers::StringAssign(mURL, inString); + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); #ifdef XP_MAC - mNativeFileSpec = inString + kFileURLPrefixLength; + mNativeFileSpec = inString + kFileURLPrefixLength; #endif } // nsFileURL::operator = @@ -215,9 +284,9 @@ void nsFileURL::operator = (const char* inString) void nsFileURL::operator = (const nsFileURL& inOther) //---------------------------------------------------------------------------------------- { - mURL = nsFileSpecHelpers::StringAssign(mURL, inOther.mURL); + mURL = nsFileSpecHelpers::StringAssign(mURL, inOther.mURL); #ifdef XP_MAC - mNativeFileSpec = inOther.GetNativeSpec(); + mNativeFileSpec = inOther.GetNativeSpec(); #endif } // nsFileURL::operator = @@ -225,10 +294,10 @@ void nsFileURL::operator = (const nsFileURL& inOther) void nsFileURL::operator = (const nsFilePath& inOther) //---------------------------------------------------------------------------------------- { - delete [] mURL; - mURL = nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)inOther); + delete [] mURL; + mURL = nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)inOther); #ifdef XP_MAC - mNativeFileSpec = inOther.GetNativeSpec(); + mNativeFileSpec = inOther.GetNativeSpec(); #endif } // nsFileURL::operator = @@ -236,10 +305,10 @@ void nsFileURL::operator = (const nsFilePath& inOther) void nsFileURL::operator = (const nsNativeFileSpec& inOther) //---------------------------------------------------------------------------------------- { - delete [] mURL; - mURL = nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)nsFilePath(inOther)); + delete [] mURL; + mURL = nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)nsFilePath(inOther)); #ifdef XP_MAC - mNativeFileSpec = inOther; + mNativeFileSpec = inOther; #endif } // nsFileURL::operator = @@ -251,26 +320,27 @@ nsOutputFileStream& operator << (nsOutputFileStream& s, const nsFileURL& url) } //======================================================================================== -// nsFilePath implementation +// nsFilePath implementation //======================================================================================== +#ifndef XP_MAC //---------------------------------------------------------------------------------------- -nsFilePath::nsFilePath(const char* inString) +nsFilePath::nsFilePath(const char* inString, bool inCreateDirs) //---------------------------------------------------------------------------------------- -: mPath(nsFileSpecHelpers::StringDup(inString)) -#ifdef XP_MAC -, mNativeFileSpec(inString) -#endif +: mPath(nsFileSpecHelpers::StringDup(inString)) { - NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); + NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); } +#endif //---------------------------------------------------------------------------------------- nsFilePath::nsFilePath(const nsFileURL& inOther) //---------------------------------------------------------------------------------------- -: mPath(nsFileSpecHelpers::StringDup(inOther.mURL + kFileURLPrefixLength)) +: mPath(nsFileSpecHelpers::StringDup(inOther.mURL + kFileURLPrefixLength)) #ifdef XP_MAC -, mNativeFileSpec(inOther.GetNativeSpec()) +, mNativeFileSpec(inOther.GetNativeSpec()) #endif { } @@ -288,7 +358,7 @@ nsFilePath::nsFilePath(const nsNativeFileSpec& inOther) nsFilePath::~nsFilePath() //---------------------------------------------------------------------------------------- { - delete [] mPath; + delete [] mPath; } #ifdef XP_UNIX @@ -304,10 +374,13 @@ void nsFilePath::operator = (const nsNativeFileSpec& inOther) void nsFilePath::operator = (const char* inString) //---------------------------------------------------------------------------------------- { - NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); - nsFileSpecHelpers::StringAssign(mPath, inString); + NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); #ifdef XP_MAC - mNativeFileSpec = inString; + mNativeFileSpec = inString; + nsFileSpecHelpers::StringAssign(mPath, (const char*)nsFilePath(mNativeFileSpec)); +#else + nsFileSpecHelpers::StringAssign(mPath, inString); + nsFileSpecHelpers::Canonify(mPath, true); #endif } @@ -315,21 +388,21 @@ void nsFilePath::operator = (const char* inString) void nsFilePath::operator = (const nsFileURL& inOther) //---------------------------------------------------------------------------------------- { - nsFileSpecHelpers::StringAssign(mPath, (const char*)nsFilePath(inOther)); + nsFileSpecHelpers::StringAssign(mPath, (const char*)nsFilePath(inOther)); #ifdef XP_MAC - mNativeFileSpec = inOther.GetNativeSpec(); + mNativeFileSpec = inOther.GetNativeSpec(); #endif } //======================================================================================== -// nsNativeFileSpec implementation +// nsNativeFileSpec implementation //======================================================================================== #ifndef XP_MAC //---------------------------------------------------------------------------------------- nsNativeFileSpec::nsNativeFileSpec() //---------------------------------------------------------------------------------------- -: mPath(NULL) +: mPath(NULL) { } #endif @@ -338,7 +411,7 @@ nsNativeFileSpec::nsNativeFileSpec() nsNativeFileSpec::nsNativeFileSpec(const nsFileURL& inURL) //---------------------------------------------------------------------------------------- #ifndef XP_MAC -: mPath(NULL) +: mPath(NULL) #endif { *this = nsFilePath(inURL); // convert to unix path first @@ -348,44 +421,44 @@ nsNativeFileSpec::nsNativeFileSpec(const nsFileURL& inURL) void nsNativeFileSpec::MakeUnique(const char* inSuggestedLeafName) //---------------------------------------------------------------------------------------- { - if (inSuggestedLeafName && *inSuggestedLeafName) - SetLeafName(inSuggestedLeafName); + if (inSuggestedLeafName && *inSuggestedLeafName) + SetLeafName(inSuggestedLeafName); - MakeUnique(); + MakeUnique(); } // nsNativeFileSpec::MakeUnique //---------------------------------------------------------------------------------------- void nsNativeFileSpec::MakeUnique() //---------------------------------------------------------------------------------------- { - if (!Exists()) - return; + if (!Exists()) + return; - char* leafName = GetLeafName(); - if (!leafName) - return; + char* leafName = GetLeafName(); + if (!leafName) + return; - char* lastDot = strrchr(leafName, '.'); - char* suffix = ""; - if (lastDot) - { - suffix = nsFileSpecHelpers::StringDup(lastDot); // include '.' - *lastDot = '\0'; // strip suffix and dot. - } - const int kMaxRootLength - = nsFileSpecHelpers::kMaxCoreLeafNameLength - strlen(suffix) - 1; - if (strlen(leafName) > kMaxRootLength) - leafName[kMaxRootLength] = '\0'; - for (short index = 1; index < 1000 && Exists(); index++) - { - // start with "Picture-1.jpg" after "Picture.jpg" exists - char newName[nsFileSpecHelpers::kMaxFilenameLength + 1]; - sprintf(newName, "%s-%d%s", leafName, index, suffix); - SetLeafName(newName); - } - if (*suffix) - delete [] suffix; - delete [] leafName; + char* lastDot = strrchr(leafName, '.'); + char* suffix = ""; + if (lastDot) + { + suffix = nsFileSpecHelpers::StringDup(lastDot); // include '.' + *lastDot = '\0'; // strip suffix and dot. + } + const int kMaxRootLength + = nsFileSpecHelpers::kMaxCoreLeafNameLength - strlen(suffix) - 1; + if (strlen(leafName) > kMaxRootLength) + leafName[kMaxRootLength] = '\0'; + for (short index = 1; index < 1000 && Exists(); index++) + { + // start with "Picture-1.jpg" after "Picture.jpg" exists + char newName[nsFileSpecHelpers::kMaxFilenameLength + 1]; + sprintf(newName, "%s-%d%s", leafName, index, suffix); + SetLeafName(newName); + } + if (*suffix) + delete [] suffix; + delete [] leafName; } // nsNativeFileSpec::MakeUnique //---------------------------------------------------------------------------------------- @@ -428,10 +501,12 @@ nsNativeFileSpec::nsNativeFileSpec(const nsNativeFileSpec& inSpec) #if defined(XP_UNIX) || defined(XP_PC) //---------------------------------------------------------------------------------------- -nsNativeFileSpec::nsNativeFileSpec(const char* inString) +nsNativeFileSpec::nsNativeFileSpec(const char* inString, bool inCreateDirs) //---------------------------------------------------------------------------------------- : mPath(nsFileSpecHelpers::StringDup(inString)) { + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); } #endif //XP_UNIX,PC @@ -440,7 +515,7 @@ nsNativeFileSpec::~nsNativeFileSpec() //---------------------------------------------------------------------------------------- { #ifndef XP_MAC - delete [] mPath; + delete [] mPath; #endif } @@ -472,3 +547,12 @@ nsOutputFileStream& operator << (nsOutputFileStream& s, const nsNativeFileSpec& } #endif // DEBUG && XP_UNIX +//---------------------------------------------------------------------------------------- +nsNativeFileSpec nsNativeFileSpec::operator + (const char* inRelativePath) const +//---------------------------------------------------------------------------------------- +{ + nsNativeFileSpec result = *this; + result += inRelativePath; + return result; +} // nsNativeFileSpec::operator + + diff --git a/mozilla/base/src/unix/nsFileSpecUnix.cpp b/mozilla/base/src/unix/nsFileSpecUnix.cpp index 357ee8d1ed6..26ecae33505 100644 --- a/mozilla/base/src/unix/nsFileSpecUnix.cpp +++ b/mozilla/base/src/unix/nsFileSpecUnix.cpp @@ -16,27 +16,205 @@ * Reserved. */ -// This file is included by nsFileSpec.cpp, and includes the Unix-specific -// implementations. +// This file is included by nsFileSpec.cpp, and includes the Unix-specific +// implementations. + +#include +#include +#include +#include +#include +#include + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(char*& ioPath, bool inMakeDirs) +// Canonify, make absolute, and check whether directories exist +//---------------------------------------------------------------------------------------- +{ + if (!ioPath) + return; + if (inMakeDirs) + { + const mode_t mode = 0700; + nsFileSpecHelpers::MakeAllDirectories(ioPath, mode); + } + char buffer[MAXPATHLEN]; + errno = 0; + *buffer = '\0'; + char* canonicalPath = realpath(ioPath, buffer); + if (!canonicalPath) + { + // Linux's realpath() is pathetically buggy. If the reason for the nil + // result is just that the leaf does not exist, strip the leaf off, + // process that, and then add the leaf back. + char* allButLeaf = nsFileSpecHelpers::StringDup(ioPath); + if (!allButLeaf) + return; + char* lastSeparator = strrchr(allButLeaf, '/'); + if (lastSeparator) + { + *lastSeparator = '\0'; + canonicalPath = realpath(allButLeaf, buffer); + strcat(buffer, "/"); + // Add back the leaf + strcat(buffer, ++lastSeparator); + } + delete [] allButLeaf; + } + if (!canonicalPath && *ioPath != '/' && !inMakeDirs) + { + // Well, if it's a relative path, hack it ourselves. + canonicalPath = realpath(".", buffer); + if (canonicalPath) + { + strcat(canonicalPath, "/"); + strcat(canonicalPath, ioPath); + } + } + if (canonicalPath) + nsFileSpecHelpers::StringAssign(ioPath, canonicalPath); +} // nsFileSpecHelpers::Canonify //---------------------------------------------------------------------------------------- void nsNativeFileSpec::SetLeafName(const char* inLeafName) //---------------------------------------------------------------------------------------- { - nsFileSpecHelpers::LeafReplace(mPath, '/', inLeafName); + nsFileSpecHelpers::LeafReplace(mPath, '/', inLeafName); } // nsNativeFileSpec::SetLeafName //---------------------------------------------------------------------------------------- char* nsNativeFileSpec::GetLeafName() const //---------------------------------------------------------------------------------------- { - return nsFileSpecHelpers::GetLeaf(mPath, '/'); + return nsFileSpecHelpers::GetLeaf(mPath, '/'); } // nsNativeFileSpec::GetLeafName //---------------------------------------------------------------------------------------- bool nsNativeFileSpec::Exists() const //---------------------------------------------------------------------------------------- { - return false; // fixme + struct stat st; + return 0 == stat(mPath, &st); } // nsNativeFileSpec::Exists +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return 0 == stat(mPath, &st) && S_ISREG(st.st_mode); +} // nsNativeFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return 0 == stat(mPath, &st) && S_ISDIR(st.st_mode); +} // nsNativeFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::GetParent(nsNativeFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + nsFileSpecHelpers::StringAssign(outSpec.mPath, mPath); + char* cp = strrchr(outSpec.mPath, '/'); + if (cp) + *cp = '\0'; +} // nsNativeFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + if (!inRelativePath || !mPath) + return; + + if (mPath[strlen(mPath) - 1] != '/') + char* newPath = nsFileSpecHelpers::ReallocCat(mPath, "/"); + SetLeafName(inRelativePath); +} // nsNativeFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::CreateDirectory(int mode) +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + mkdir(mPath, mode); +} // nsNativeFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::Delete(bool inRecursive) +// To check if this worked, call Exists() afterwards, see? +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this); i; i++) + { + nsNativeFileSpec& child = (nsNativeFileSpec&)i; + child.Delete(inRecursive); + } + } + rmdir(mPath); + } + else + remove(mPath); +} // nsNativeFileSpec::Delete + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator( + const nsNativeFileSpec& inDirectory +, int inIterateDirection) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mDir(nsnull) + , mExists(false) +{ + mCurrent += "sysygy"; // prepare the path for SetLeafName + mDir = opendir((const char*)nsFilePath(inDirectory)); + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ + if (mDir) + closedir(mDir); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = false; + if (!mDir) + return *this; + char* dot = "."; + char* dotdot = ".."; + struct dirent* entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dot) == 0) + entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dotdot) == 0) + entry = readdir(mDir); + if (entry) + { + mExists = true; + mCurrent.SetLeafName(entry->d_name); + } + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- diff --git a/mozilla/base/src/windows/nsFileSpecWin.cpp b/mozilla/base/src/windows/nsFileSpecWin.cpp index d66fe1f457b..a33bd817cf1 100644 --- a/mozilla/base/src/windows/nsFileSpecWin.cpp +++ b/mozilla/base/src/windows/nsFileSpecWin.cpp @@ -19,6 +19,17 @@ // This file is included by nsFileSpec.cp, and includes the Windows-specific // implementations. +#include + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(char*& ioPath, bool inMakeDirs) +// Canonify, make absolute, and check whether directories exist +//---------------------------------------------------------------------------------------- +{ + NS_NOTYETIMPLEMENTED("Please, some Winhead please write this!"); + return ioPath; +} + //---------------------------------------------------------------------------------------- nsNativeFileSpec::nsNativeFileSpec(const nsFilePath& inPath) //---------------------------------------------------------------------------------------- @@ -31,9 +42,17 @@ nsNativeFileSpec::nsNativeFileSpec(const nsFilePath& inPath) void nsNativeFileSpec::operator = (const nsFilePath& inPath) //---------------------------------------------------------------------------------------- { - // Convert '/' to '\' - nsFileSpecHelpers::StringAssign(mPath, (const char*)inPath); - for (char* cp = mPath; *cp; cp++) + // Strip the leading slash, which should + // leave us pointing to a drive letter. + nsFileSpecHelpers::StringAssign(mPath, (const char*)inPath + 1); + + // Convert the vertical slash to a colon + char* cp = mPath + 1; + if (strstr(cp, "|/") == cp) + *cp = ':'; + + // Convert '/' to '\'. + while (*++cp) { if (*cp == '/') *cp = '\\'; @@ -79,6 +98,138 @@ char* nsNativeFileSpec::GetLeafName() const bool nsNativeFileSpec::Exists() const //---------------------------------------------------------------------------------------- { - return false; // fixme + struct stat st; + return 0 == stat(mPath, &st); } // nsNativeFileSpec::Exists +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return 0 == stat(mPath, &st) && S_ISREG(st.st_mode); +} // nsNativeFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return 0 == stat(mPath, &st) && S_ISDIR(st.st_mode); +} // nsNativeFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::GetParent(nsNativeFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + nsFileSpecHelpers::StringAssign(outSpec.mPath, mPath); + char* cp = strrchr(outSpec.mPath, '\\'); + if (cp) + *cp = '\0'; +} // nsNativeFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + if (!inRelativePath || !mPath) + return; + + if (mPath[strlen(mPath) - 1] != '\\') + char* newPath = nsFileSpecHelpers::ReallocCat(mPath, "\\"); + SetLeafName(inRelativePath); +} // nsNativeFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::CreateDirectory() +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + NS_NOTYETIMPLEMENTED("Please, some Winhead please fix this!"); + mkdir(mPath, mode); +} // nsNativeFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::Delete(bool inRecursive) +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this); i; i++) + { + const nsNativeFileSpec& child = (nsNativeFileSpec&)i; + child.Delete(inRecursive); + } + } + NS_NOTYETIMPLEMENTED("Please, some Winhead please fix this!"); + rmdir(mPath); + } + else + { + NS_NOTYETIMPLEMENTED("Please, some Winhead please write this!"); + remove(mPath); + } +} // nsNativeFileSpec::Delete + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator( + const nsNativeFileSpec& inDirectory +, int inIterateDirection) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) +#if 0 // Some kind winhead please build, test, and remove when ready. + , mDir(nsnull) +#endif // XP_PC -- ifdef to be removed. + , mExists(false) +{ +NS_NOTYETIMPLEMENTED("Please, some kind Winhead please check this!"); + mCurrent += "foo"; +#if 0 // Some kind winhead please build, test, and remove when ready. + mDir = opendir(mPath); +#endif // XP_PC -- ifdef to be removed. + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ +NS_NOTYETIMPLEMENTED("Please, some kind Winhead please check this!"); +#if 0 // Some kind winhead please build, test, and remove when ready. + if (mDir) + closedir(mDir); +#endif // XP_PC -- ifdef to be removed. +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = false; +NS_NOTYETIMPLEMENTED("Please, some kind Winhead please check this!"); +#if 0 // Some kind winhead please build, test, and remove when ready. + if (!mDir) + return *this; + struct dirent* entry = readdir(mDir); + if (entry) + { + mExists = true; + mCurrent.SetLeafName(entry->d_name); + } +#endif // XP_PC -- ifdef to be removed. + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- + diff --git a/mozilla/base/tests/FilesTest.cpp b/mozilla/base/tests/FilesTest.cpp index 31e09e909b3..c134764a0bd 100644 --- a/mozilla/base/tests/FilesTest.cpp +++ b/mozilla/base/tests/FilesTest.cpp @@ -11,7 +11,7 @@ void FilesTest::WriteStuff(nsOutputFileStream& s) //---------------------------------------------------------------------------------------- { // Initialize a URL from a string without suffix. Change the path to suit your machine. - nsFileURL fileURL("file:///Development/MPW/MPW%20Shell"); + nsFileURL fileURL("file:///Development/MPW/MPW%20Shell", false); s << "File URL initialized to: \"" << fileURL << "\""<< nsEndl; // Initialize a Unix path from a URL @@ -44,7 +44,7 @@ void FilesTest::WriteStuff(nsOutputFileStream& s) } // WriteStuff //---------------------------------------------------------------------------------------- -void main() +int main() // For use with DEBUG defined. //---------------------------------------------------------------------------------------- { @@ -59,38 +59,59 @@ void main() FilesTest::WriteStuff(nsOut); nsOut << nsEndl << nsEndl; - // Test of nsOutputFileStream - - nsFilePath myTextFilePath("iotest.txt"); + // - Test of nsOutputFileStream + nsFilePath myTextFilePath("mumble/iotest.txt", true); // relative path. + const char* pathAsString = (const char*)myTextFilePath; + if (*pathAsString != '/') { - nsOut << "WRITING IDENTICAL OUTPUT TO " << (const char*)myTextFilePath << nsEndl << nsEndl; + nsOut + << "ERROR: after initializing the path object with a relative path," + << "\n the path consisted of the string " + << "\n\t" << pathAsString + << "\n which is not a canonical full path!" + << nsEndl; + return -1; + } + + nsNativeFileSpec mySpec(myTextFilePath); + { + nsOut << "WRITING IDENTICAL OUTPUT TO " << pathAsString << nsEndl << nsEndl; nsOutputFileStream testStream(myTextFilePath); if (!testStream.is_open()) { nsOut << "ERROR: File " - << (const char*)myTextFilePath + << pathAsString << " could not be opened for output" << nsEndl; - return; + return -1; } FilesTest::WriteStuff(testStream); } // <-- Scope closes the stream (and the file). - // Test of nsInputFileStream + if (!mySpec.Exists() || mySpec.IsDirectory() || !mySpec.IsFile()) + { + nsOut + << "ERROR: File " + << pathAsString + << " is not a file (cela n'est pas un pipe)" + << nsEndl; + return -1; + } + // - Test of nsInputFileStream { - nsOut << "READING BACK DATA FROM " << (const char*)myTextFilePath << nsEndl << nsEndl; + nsOut << "READING BACK DATA FROM " << pathAsString << nsEndl << nsEndl; nsInputFileStream testStream2(myTextFilePath); if (!testStream2.is_open()) { nsOut << "ERROR: File " - << (const char*)myTextFilePath + << pathAsString << " could not be opened for input" << nsEndl; - return; + return -1; } char line[1000]; @@ -101,4 +122,101 @@ void main() nsOut << line << nsEndl; } } // <-- Scope closes the stream (and the file). + + // - Test of GetParent() + + nsNativeFileSpec parent; + mySpec.GetParent(parent); + nsFilePath parentPath(parent); + nsOut + << "GetParent() on " + << "\n\t" << pathAsString + << "\n yields " + << "\n\t" << (const char*)parentPath + << nsEndl; + + // - Test of non-recursive delete + + nsOut + << "Attempting to delete " + << "\n\t" << (const char*)parentPath + << "\n without recursive option (should fail)" + << nsEndl; + parent.Delete(false); + if (parent.Exists()) + nsOut << "Test passed." << nsEndl; + else + { + nsOut + << "ERROR: File " + << "\n\t" << (const char*)parentPath + << "\n has been deleted without the recursion option," + << "\n and is a nonempty directory!" + << nsEndl; + return -1; + } + + // - Test of recursive delete + + nsOut + << "Deleting " + << "\n\t" << (const char*)parentPath + << "\n with recursive option" + << nsEndl; + parent.Delete(true); + if (parent.Exists()) + { + nsOut + << "ERROR: Directory " + << "\n\t" << (const char*)parentPath + << "\n has NOT been deleted despite the recursion option!" + << nsEndl; + return -1; + } + else + nsOut << "Test passed." << nsEndl; + + // - Test of CreateDirectory + + nsOut + << "Testing CreateDirectory() using" + << "\n\t" << (const char*)parentPath + << nsEndl; + + parent.CreateDirectory(); + if (parent.Exists()) + nsOut << "Test passed." << nsEndl; + else + { + nsOut << "ERROR: Test failed." << nsEndl; + return -1; + } + parent.Delete(true); + +#ifndef XP_PC // uncomment when tested and ready. + + // - Test of directory iterator + + nsNativeFileSpec grandparent; + parent.GetParent(grandparent); // should be the original default directory. + nsFilePath grandparentPath(grandparent); + + nsOut << "Forwards listing of " << (const char*)grandparentPath << ":" << nsEndl; + for (nsDirectoryIterator i(grandparent, +1); i; i++) + { + char* itemName = ((nsNativeFileSpec&)i).GetLeafName(); + nsOut << '\t' << itemName << nsEndl; + delete [] itemName; + } + + nsOut << "Backwards listing of " << (const char*)grandparentPath << ":" << nsEndl; + for (nsDirectoryIterator i(grandparent, -1); i; i--) + { + char* itemName = ((nsNativeFileSpec&)i).GetLeafName(); + nsOut << '\t' << itemName << nsEndl; + delete [] itemName; + } +#endif + + return 0; } // main diff --git a/mozilla/xpcom/io/nsFileSpec.cpp b/mozilla/xpcom/io/nsFileSpec.cpp index df710c9a814..7a6403eea15 100644 --- a/mozilla/xpcom/io/nsFileSpec.cpp +++ b/mozilla/xpcom/io/nsFileSpec.cpp @@ -30,115 +30,180 @@ NS_NAMESPACE nsFileSpecHelpers //======================================================================================== { - enum - { kMaxFilenameLength = 31 // should work on Macintosh, Unix, and Win32. - , kMaxAltDigitLength = 5 - , kMaxCoreLeafNameLength = (kMaxFilenameLength - (kMaxAltDigitLength + 1)) - }; - NS_NAMESPACE_PROTOTYPE void LeafReplace( - char*& ioPath, - char inSeparator, - const char* inLeafName); - NS_NAMESPACE_PROTOTYPE char* GetLeaf(const char* inPath, char inSeparator); // allocated - NS_NAMESPACE_PROTOTYPE char* StringDup(const char* inString, int allocLength = 0); - NS_NAMESPACE_PROTOTYPE char* AllocCat(const char* inString1, const char* inString2); - NS_NAMESPACE_PROTOTYPE char* StringAssign(char*& ioString, const char* inOther); + enum + { kMaxFilenameLength = 31 // should work on Macintosh, Unix, and Win32. + , kMaxAltDigitLength = 5 + , kMaxCoreLeafNameLength = (kMaxFilenameLength - (kMaxAltDigitLength + 1)) + }; + NS_NAMESPACE_PROTOTYPE void LeafReplace( + char*& ioPath, + char inSeparator, + const char* inLeafName); +#ifndef XP_MAC + NS_NAMESPACE_PROTOTYPE void Canonify(char*& ioPath, bool inMakeDirs); + NS_NAMESPACE_PROTOTYPE void MakeAllDirectories(const char* inPath, int mode); +#endif + NS_NAMESPACE_PROTOTYPE char* GetLeaf(const char* inPath, char inSeparator); // allocated + NS_NAMESPACE_PROTOTYPE char* StringDup(const char* inString, int allocLength = 0); + NS_NAMESPACE_PROTOTYPE char* AllocCat(const char* inString1, const char* inString2); + NS_NAMESPACE_PROTOTYPE char* StringAssign(char*& ioString, const char* inOther); + NS_NAMESPACE_PROTOTYPE char* ReallocCat(char*& ioString, const char* inString1); } NS_NAMESPACE_END + //---------------------------------------------------------------------------------------- char* nsFileSpecHelpers::StringDup( - const char* inString, - int allocLength) + const char* inString, + int allocLength) //---------------------------------------------------------------------------------------- { - if (!allocLength && inString) - allocLength = strlen(inString); - char* newPath = inString || allocLength ? new char[allocLength + 1] : 0; - if (!newPath) - return NULL; - strcpy(newPath, inString); - return newPath; + if (!allocLength && inString) + allocLength = strlen(inString); + char* newPath = inString || allocLength ? new char[allocLength + 1] : nsnull; + if (!newPath) + return NULL; + strcpy(newPath, inString); + return newPath; } // nsFileSpecHelpers::StringDup //---------------------------------------------------------------------------------------- char* nsFileSpecHelpers::AllocCat( - const char* inString1, - const char* inString2) + const char* inString1, + const char* inString2) //---------------------------------------------------------------------------------------- { - if (!inString1) - return inString2 ? StringDup(inString2) : (char*)NULL; - if (!inString2) - return StringDup(inString1); - char* outString = StringDup(inString1, strlen(inString1) + strlen(inString2)); - if (outString) - strcat(outString, inString2); - return outString; + if (!inString1) + return inString2 ? StringDup(inString2) : (char*)NULL; + if (!inString2) + return StringDup(inString1); + char* outString = StringDup(inString1, strlen(inString1) + strlen(inString2)); + if (outString) + strcat(outString, inString2); + return outString; } // nsFileSpecHelpers::StringDup //---------------------------------------------------------------------------------------- char* nsFileSpecHelpers::StringAssign( - char*& ioString, - const char* inString2) + char*& ioString, + const char* inString2) //---------------------------------------------------------------------------------------- { - if (!inString2) - { - delete [] ioString; - ioString = (char*)NULL; - return ioString; - } - if (!ioString || (strlen(inString2) > strlen(ioString))) - { - delete [] ioString; - ioString = StringDup(inString2); - return ioString; - } - strcpy(ioString, inString2); - return ioString; + if (!inString2) + { + delete [] ioString; + ioString = (char*)NULL; + return ioString; + } + if (!ioString || (strlen(inString2) > strlen(ioString))) + { + delete [] ioString; + ioString = StringDup(inString2); + return ioString; + } + strcpy(ioString, inString2); + return ioString; } // nsFileSpecHelpers::StringAssign //---------------------------------------------------------------------------------------- void nsFileSpecHelpers::LeafReplace( - char*& ioPath, - char inSeparator, - const char* inLeafName) + char*& ioPath, + char inSeparator, + const char* inLeafName) //---------------------------------------------------------------------------------------- { - // Find the existing leaf name - if (!ioPath) - return; - if (!inLeafName) - { - *ioPath = '\0'; - return; - } - char* lastSeparator = strrchr(ioPath, inSeparator); - int oldLength = strlen(ioPath); - *(++lastSeparator) = '\0'; // strip the current leaf name - int newLength = lastSeparator - ioPath + strlen(inLeafName); - if (newLength > oldLength) - { - char* newPath = StringDup(ioPath, newLength + 1); - delete [] ioPath; - ioPath = newPath; - } - strcat(ioPath, inLeafName); -} // nsNativeFileSpec::SetLeafName + // Find the existing leaf name + if (!ioPath) + return; + if (!inLeafName) + { + *ioPath = '\0'; + return; + } + char* lastSeparator = strrchr(ioPath, inSeparator); + int oldLength = strlen(ioPath); + *(++lastSeparator) = '\0'; // strip the current leaf name + int newLength = lastSeparator - ioPath + strlen(inLeafName); + if (newLength > oldLength) + { + char* newPath = StringDup(ioPath, newLength + 1); + delete [] ioPath; + ioPath = newPath; + } + strcat(ioPath, inLeafName); +} // nsNativeFileSpec::LeafReplace //---------------------------------------------------------------------------------------- char* nsFileSpecHelpers::GetLeaf(const char* inPath, char inSeparator) // Returns a pointer to an allocated string representing the leaf. //---------------------------------------------------------------------------------------- { - if (!inPath) - return NULL; - char* lastSeparator = strrchr(inPath, inSeparator); - if (lastSeparator) - return StringDup(lastSeparator); - return StringDup(inPath); + if (!inPath) + return NULL; + char* lastSeparator = strrchr(inPath, inSeparator); + if (lastSeparator) + return StringDup(++lastSeparator); + return StringDup(inPath); } // nsNativeFileSpec::GetLeaf +#if defined(XP_UNIX) || defined(XP_PC) + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::MakeAllDirectories(const char* inPath, int mode) +// Make the path a valid one by creating all the intermediate directories. Does NOT +// make the leaf into a directory. This should be a unix path. +//---------------------------------------------------------------------------------------- +{ + if (!inPath) + return; + + char* pathCopy = nsFileSpecHelpers::StringDup( inPath ); + if (!pathCopy) + return; + + const char kSeparator = '/'; // I repeat: this should be a unix-style path. + const int kSkipFirst = 1; + +#ifdef XP_WIN + NS_ASSERTION( pathCopy[2] == '|', "No drive letter!" ); +#endif + char* currentStart = pathCopy; + char* currentEnd = strchr(currentStart + kSkipFirst, kSeparator); + if (currentEnd) + { + *currentEnd = '\0'; + nsNativeFileSpec spec(nsFilePath(pathCopy, false)); + do + { + // If the node doesn't exist, and it is not the initial node in a full path, + // then make a directory (We cannot make the initial (volume) node). + if (!spec.Exists() && *currentStart != kSeparator) + spec.CreateDirectory(mode); + if (!spec.Exists()) + { + NS_ASSERTION(spec.Exists(), "Could not create the directory?"); + break; + } + currentStart = ++currentEnd; + currentEnd = strchr(currentStart, kSeparator); + if (!currentEnd) + break; + spec += currentStart; // "lengthen" the path, adding the next node. + } while (currentEnd); + } + delete [] pathCopy; +} // nsFileSpecHelpers::MakeAllDirectories + +#endif // XP_PC || XP_UNIX + +//---------------------------------------------------------------------------------------- +char* nsFileSpecHelpers::ReallocCat(char*& ioString, const char* inString1) +//---------------------------------------------------------------------------------------- +{ + char* newString = AllocCat(ioString, inString1); + delete [] ioString; + ioString = newString; + return ioString; +} // nsNativeFileSpec::ReallocCat #if defined(XP_PC) #include "windows/nsFileSpecWin.cpp" // Windows-specific implementations @@ -149,26 +214,30 @@ char* nsFileSpecHelpers::GetLeaf(const char* inPath, char inSeparator) #endif //======================================================================================== -// nsFileURL implementation +// nsFileURL implementation //======================================================================================== +#ifndef XP_MAC //---------------------------------------------------------------------------------------- -nsFileURL::nsFileURL(const char* inString) +nsFileURL::nsFileURL(const char* inString, bool inCreateDirs) //---------------------------------------------------------------------------------------- -: mURL(nsFileSpecHelpers::StringDup(inString)) -#ifdef XP_MAC -, mNativeFileSpec(inString + kFileURLPrefixLength) -#endif +: mURL(nsnull) { - NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + if (!inString) + return; + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + // Make canonical and absolute. + nsFilePath path(inString + kFileURLPrefixLength, inCreateDirs); + *this = path; } // nsFileURL::nsFileURL +#endif //---------------------------------------------------------------------------------------- nsFileURL::nsFileURL(const nsFileURL& inOther) //---------------------------------------------------------------------------------------- -: mURL(nsFileSpecHelpers::StringDup(inOther.mURL)) +: mURL(nsFileSpecHelpers::StringDup(inOther.mURL)) #ifdef XP_MAC -, mNativeFileSpec(inOther.GetNativeSpec()) +, mNativeFileSpec(inOther.GetNativeSpec()) #endif { } // nsFileURL::nsFileURL @@ -176,18 +245,18 @@ nsFileURL::nsFileURL(const nsFileURL& inOther) //---------------------------------------------------------------------------------------- nsFileURL::nsFileURL(const nsFilePath& inOther) //---------------------------------------------------------------------------------------- -: mURL(nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)inOther)) +: mURL(nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)inOther)) #ifdef XP_MAC -, mNativeFileSpec(inOther.GetNativeSpec()) +, mNativeFileSpec(inOther.GetNativeSpec()) #endif { } // nsFileURL::nsFileURL //---------------------------------------------------------------------------------------- nsFileURL::nsFileURL(const nsNativeFileSpec& inOther) -: mURL(nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)nsFilePath(inOther))) +: mURL(nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)nsFilePath(inOther))) #ifdef XP_MAC -, mNativeFileSpec(inOther) +, mNativeFileSpec(inOther) #endif //---------------------------------------------------------------------------------------- { @@ -197,17 +266,17 @@ nsFileURL::nsFileURL(const nsNativeFileSpec& inOther) nsFileURL::~nsFileURL() //---------------------------------------------------------------------------------------- { - delete [] mURL; + delete [] mURL; } //---------------------------------------------------------------------------------------- void nsFileURL::operator = (const char* inString) //---------------------------------------------------------------------------------------- { - nsFileSpecHelpers::StringAssign(mURL, inString); - NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + nsFileSpecHelpers::StringAssign(mURL, inString); + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); #ifdef XP_MAC - mNativeFileSpec = inString + kFileURLPrefixLength; + mNativeFileSpec = inString + kFileURLPrefixLength; #endif } // nsFileURL::operator = @@ -215,9 +284,9 @@ void nsFileURL::operator = (const char* inString) void nsFileURL::operator = (const nsFileURL& inOther) //---------------------------------------------------------------------------------------- { - mURL = nsFileSpecHelpers::StringAssign(mURL, inOther.mURL); + mURL = nsFileSpecHelpers::StringAssign(mURL, inOther.mURL); #ifdef XP_MAC - mNativeFileSpec = inOther.GetNativeSpec(); + mNativeFileSpec = inOther.GetNativeSpec(); #endif } // nsFileURL::operator = @@ -225,10 +294,10 @@ void nsFileURL::operator = (const nsFileURL& inOther) void nsFileURL::operator = (const nsFilePath& inOther) //---------------------------------------------------------------------------------------- { - delete [] mURL; - mURL = nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)inOther); + delete [] mURL; + mURL = nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)inOther); #ifdef XP_MAC - mNativeFileSpec = inOther.GetNativeSpec(); + mNativeFileSpec = inOther.GetNativeSpec(); #endif } // nsFileURL::operator = @@ -236,10 +305,10 @@ void nsFileURL::operator = (const nsFilePath& inOther) void nsFileURL::operator = (const nsNativeFileSpec& inOther) //---------------------------------------------------------------------------------------- { - delete [] mURL; - mURL = nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)nsFilePath(inOther)); + delete [] mURL; + mURL = nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)nsFilePath(inOther)); #ifdef XP_MAC - mNativeFileSpec = inOther; + mNativeFileSpec = inOther; #endif } // nsFileURL::operator = @@ -251,26 +320,27 @@ nsOutputFileStream& operator << (nsOutputFileStream& s, const nsFileURL& url) } //======================================================================================== -// nsFilePath implementation +// nsFilePath implementation //======================================================================================== +#ifndef XP_MAC //---------------------------------------------------------------------------------------- -nsFilePath::nsFilePath(const char* inString) +nsFilePath::nsFilePath(const char* inString, bool inCreateDirs) //---------------------------------------------------------------------------------------- -: mPath(nsFileSpecHelpers::StringDup(inString)) -#ifdef XP_MAC -, mNativeFileSpec(inString) -#endif +: mPath(nsFileSpecHelpers::StringDup(inString)) { - NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); + NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); } +#endif //---------------------------------------------------------------------------------------- nsFilePath::nsFilePath(const nsFileURL& inOther) //---------------------------------------------------------------------------------------- -: mPath(nsFileSpecHelpers::StringDup(inOther.mURL + kFileURLPrefixLength)) +: mPath(nsFileSpecHelpers::StringDup(inOther.mURL + kFileURLPrefixLength)) #ifdef XP_MAC -, mNativeFileSpec(inOther.GetNativeSpec()) +, mNativeFileSpec(inOther.GetNativeSpec()) #endif { } @@ -288,7 +358,7 @@ nsFilePath::nsFilePath(const nsNativeFileSpec& inOther) nsFilePath::~nsFilePath() //---------------------------------------------------------------------------------------- { - delete [] mPath; + delete [] mPath; } #ifdef XP_UNIX @@ -304,10 +374,13 @@ void nsFilePath::operator = (const nsNativeFileSpec& inOther) void nsFilePath::operator = (const char* inString) //---------------------------------------------------------------------------------------- { - NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); - nsFileSpecHelpers::StringAssign(mPath, inString); + NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); #ifdef XP_MAC - mNativeFileSpec = inString; + mNativeFileSpec = inString; + nsFileSpecHelpers::StringAssign(mPath, (const char*)nsFilePath(mNativeFileSpec)); +#else + nsFileSpecHelpers::StringAssign(mPath, inString); + nsFileSpecHelpers::Canonify(mPath, true); #endif } @@ -315,21 +388,21 @@ void nsFilePath::operator = (const char* inString) void nsFilePath::operator = (const nsFileURL& inOther) //---------------------------------------------------------------------------------------- { - nsFileSpecHelpers::StringAssign(mPath, (const char*)nsFilePath(inOther)); + nsFileSpecHelpers::StringAssign(mPath, (const char*)nsFilePath(inOther)); #ifdef XP_MAC - mNativeFileSpec = inOther.GetNativeSpec(); + mNativeFileSpec = inOther.GetNativeSpec(); #endif } //======================================================================================== -// nsNativeFileSpec implementation +// nsNativeFileSpec implementation //======================================================================================== #ifndef XP_MAC //---------------------------------------------------------------------------------------- nsNativeFileSpec::nsNativeFileSpec() //---------------------------------------------------------------------------------------- -: mPath(NULL) +: mPath(NULL) { } #endif @@ -338,7 +411,7 @@ nsNativeFileSpec::nsNativeFileSpec() nsNativeFileSpec::nsNativeFileSpec(const nsFileURL& inURL) //---------------------------------------------------------------------------------------- #ifndef XP_MAC -: mPath(NULL) +: mPath(NULL) #endif { *this = nsFilePath(inURL); // convert to unix path first @@ -348,44 +421,44 @@ nsNativeFileSpec::nsNativeFileSpec(const nsFileURL& inURL) void nsNativeFileSpec::MakeUnique(const char* inSuggestedLeafName) //---------------------------------------------------------------------------------------- { - if (inSuggestedLeafName && *inSuggestedLeafName) - SetLeafName(inSuggestedLeafName); + if (inSuggestedLeafName && *inSuggestedLeafName) + SetLeafName(inSuggestedLeafName); - MakeUnique(); + MakeUnique(); } // nsNativeFileSpec::MakeUnique //---------------------------------------------------------------------------------------- void nsNativeFileSpec::MakeUnique() //---------------------------------------------------------------------------------------- { - if (!Exists()) - return; + if (!Exists()) + return; - char* leafName = GetLeafName(); - if (!leafName) - return; + char* leafName = GetLeafName(); + if (!leafName) + return; - char* lastDot = strrchr(leafName, '.'); - char* suffix = ""; - if (lastDot) - { - suffix = nsFileSpecHelpers::StringDup(lastDot); // include '.' - *lastDot = '\0'; // strip suffix and dot. - } - const int kMaxRootLength - = nsFileSpecHelpers::kMaxCoreLeafNameLength - strlen(suffix) - 1; - if (strlen(leafName) > kMaxRootLength) - leafName[kMaxRootLength] = '\0'; - for (short index = 1; index < 1000 && Exists(); index++) - { - // start with "Picture-1.jpg" after "Picture.jpg" exists - char newName[nsFileSpecHelpers::kMaxFilenameLength + 1]; - sprintf(newName, "%s-%d%s", leafName, index, suffix); - SetLeafName(newName); - } - if (*suffix) - delete [] suffix; - delete [] leafName; + char* lastDot = strrchr(leafName, '.'); + char* suffix = ""; + if (lastDot) + { + suffix = nsFileSpecHelpers::StringDup(lastDot); // include '.' + *lastDot = '\0'; // strip suffix and dot. + } + const int kMaxRootLength + = nsFileSpecHelpers::kMaxCoreLeafNameLength - strlen(suffix) - 1; + if (strlen(leafName) > kMaxRootLength) + leafName[kMaxRootLength] = '\0'; + for (short index = 1; index < 1000 && Exists(); index++) + { + // start with "Picture-1.jpg" after "Picture.jpg" exists + char newName[nsFileSpecHelpers::kMaxFilenameLength + 1]; + sprintf(newName, "%s-%d%s", leafName, index, suffix); + SetLeafName(newName); + } + if (*suffix) + delete [] suffix; + delete [] leafName; } // nsNativeFileSpec::MakeUnique //---------------------------------------------------------------------------------------- @@ -428,10 +501,12 @@ nsNativeFileSpec::nsNativeFileSpec(const nsNativeFileSpec& inSpec) #if defined(XP_UNIX) || defined(XP_PC) //---------------------------------------------------------------------------------------- -nsNativeFileSpec::nsNativeFileSpec(const char* inString) +nsNativeFileSpec::nsNativeFileSpec(const char* inString, bool inCreateDirs) //---------------------------------------------------------------------------------------- : mPath(nsFileSpecHelpers::StringDup(inString)) { + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); } #endif //XP_UNIX,PC @@ -440,7 +515,7 @@ nsNativeFileSpec::~nsNativeFileSpec() //---------------------------------------------------------------------------------------- { #ifndef XP_MAC - delete [] mPath; + delete [] mPath; #endif } @@ -472,3 +547,12 @@ nsOutputFileStream& operator << (nsOutputFileStream& s, const nsNativeFileSpec& } #endif // DEBUG && XP_UNIX +//---------------------------------------------------------------------------------------- +nsNativeFileSpec nsNativeFileSpec::operator + (const char* inRelativePath) const +//---------------------------------------------------------------------------------------- +{ + nsNativeFileSpec result = *this; + result += inRelativePath; + return result; +} // nsNativeFileSpec::operator + + diff --git a/mozilla/xpcom/io/nsFileSpec.h b/mozilla/xpcom/io/nsFileSpec.h index 1c73419c631..b27dcc6b85f 100644 --- a/mozilla/xpcom/io/nsFileSpec.h +++ b/mozilla/xpcom/io/nsFileSpec.h @@ -127,6 +127,10 @@ #ifdef XP_MAC #include +#elif defined(XP_UNIX) || defined (XP_OS2) +#include +#elif 0 // defined(XP_PC) +#include "winfile.h" #endif //======================================================================================== @@ -150,7 +154,7 @@ class NS_BASE nsNativeFileSpec { public: nsNativeFileSpec(); - explicit nsNativeFileSpec(const char* inString); + explicit nsNativeFileSpec(const char* inString, bool inCreateDirs = false); explicit nsNativeFileSpec(const nsFilePath& inPath); explicit nsNativeFileSpec(const nsFileURL& inURL); nsNativeFileSpec(const nsNativeFileSpec& inPath); @@ -177,12 +181,12 @@ class NS_BASE nsNativeFileSpec operator const FSSpec& () const { return mSpec; } OSErr Error() const { return mError; } void MakeAliasSafe(); - // Called for the spec of an alias. Copies the alias to - // a secret temp directory and modifies the spec to point - // to it. Sets mError. + // Called for the spec of an alias. Copies the alias to + // a secret temp directory and modifies the spec to point + // to it. Sets mError. void ResolveAlias(bool& wasAliased); - // Called for the spec of an alias. Modifies the spec to - // point to the original. Sets mError. + // Called for the spec of an alias. Modifies the spec to + // point to the original. Sets mError. void MakeUnique(ConstStr255Param inSuggestedLeafName); StringPtr GetLeafPName() { return mSpec.name; } ConstStr255Param GetLeafPName() const { return mSpec.name; } @@ -194,14 +198,58 @@ class NS_BASE nsNativeFileSpec bool Valid() const { return true; } // Fixme. #endif // XP_MAC - friend NS_BASE nsOutputFileStream& operator << (nsOutputFileStream& s, const nsNativeFileSpec& spec); + friend NS_BASE nsOutputFileStream& operator << ( + nsOutputFileStream& s, + const nsNativeFileSpec& spec); + + //-------------------------------------------------- + // Queries and path algebra. These do not modify the disk. + //-------------------------------------------------- char* GetLeafName() const; // Allocated. Use delete []. void SetLeafName(const char* inLeafName); - bool Exists() const; + // inLeafName can be a relative path, so this allows + // one kind of concatenation of "paths". + + void GetParent(nsNativeFileSpec& outSpec) const; + // Return the filespec of the parent directory. Used + // in conjunction with GetLeafName(), this lets you + // parse a path into a list of node names. Beware, + // however, that the top node is still not a name, + // but a spec. Volumes on Macintosh can have identical + // names. Perhaps could be used for an operator --() ? + + nsNativeFileSpec operator + (const char* inRelativePath) const; + void operator += (const char* inRelativePath); + // Concatenate the relative path to this directory. + // Used for constructing the filespec of a descendant. + // This must be a directory for this to work. This differs + // from SetLeafName(), since the latter will work + // starting with a sibling of the directory and throws + // away its leaf information, whereas this one assumes + // this is a directory, and the relative path starts + // "below" this. + void MakeUnique(); void MakeUnique(const char* inSuggestedLeafName); + bool IsDirectory() const; + // More stringent than Exists() + bool IsFile() const; + // More stringent than Exists() + bool Exists() const; + + //-------------------------------------------------- + // Creation and deletion of objects. These can modify the disk. + //-------------------------------------------------- + + void CreateDirectory(int mode = 0700 /* for unix */); + void Delete(bool inRecursive); + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + private: friend class nsFilePath; #ifdef XP_MAC @@ -221,7 +269,7 @@ class NS_BASE nsFileURL { public: nsFileURL(const nsFileURL& inURL); - explicit nsFileURL(const char* inString); + explicit nsFileURL(const char* inString, bool inCreateDirs = false); explicit nsFileURL(const nsFilePath& inPath); explicit nsFileURL(const nsNativeFileSpec& inPath); virtual ~nsFileURL(); @@ -247,7 +295,7 @@ class NS_BASE nsFileURL operator char* (); operator const char* const (); private: - friend class nsFilePath; // to allow construction of nsFilePath + friend class nsFilePath; // to allow construction of nsFilePath char* mURL; #ifdef XP_MAC // Since the path on the macintosh does not uniquely specify a file (volumes @@ -264,7 +312,7 @@ class NS_BASE nsFilePath { public: nsFilePath(const nsFilePath& inPath); - explicit nsFilePath(const char* inString); + explicit nsFilePath(const char* inString, bool inCreateDirs = false); explicit nsFilePath(const nsFileURL& inURL); explicit nsFilePath(const nsNativeFileSpec& inPath); virtual ~nsFilePath(); @@ -292,7 +340,7 @@ class NS_BASE nsFilePath private: - char* mPath; + char* mPath; #ifdef XP_MAC // Since the path on the macintosh does not uniquely specify a file (volumes // can have the same name), stash the secret nsNativeFileSpec, too. @@ -300,4 +348,52 @@ class NS_BASE nsFilePath #endif }; // class nsFilePath +//======================================================================================== +class nsDirectoryIterator +// Example: +// +// nsNativeFileSpec parentDir(...); // directory over whose children we shall iterate +// for (nsDirectoryIterator i(parentDir); i; i++) +// { +// // do something with (const nsNativeFileSpec&)i +// } +// +// or: +// +// for (nsDirectoryIterator i(parentDir, false); i; i--) +// { +// // do something with (const nsNativeFileSpec&)i +// } +// +// Currently, the only platform on which backwards iteration actually goes backwards +// is Macintosh. On other platforms, both styles will work, but will go forwards. +//======================================================================================== +{ + public: + nsDirectoryIterator( + const nsNativeFileSpec& parent, + int iterateDirection = +1); +#ifndef XP_MAC + // Macintosh currently doesn't allocate, so needn't clean up. + virtual ~nsDirectoryIterator(); +#endif + operator bool() const { return mExists; } + nsDirectoryIterator& operator ++(); // moves to the next item, if any. + nsDirectoryIterator& operator ++(int) { return ++(*this); } // post-increment. + nsDirectoryIterator& operator --(); // moves to the previous item, if any. + nsDirectoryIterator& operator --(int) { return --(*this); } // post-decrement. + operator nsNativeFileSpec&() { return mCurrent; } + private: + nsNativeFileSpec mCurrent; + bool mExists; + +#if defined(XP_UNIX) // || defined(XP_PC) add when ready + DIR* mDir; +#elif defined(XP_MAC) + OSErr SetToIndex(); + short mIndex; + short mMaxIndex; +#endif +}; // class nsDirectoryIterator + #endif // _FILESPEC_H_ diff --git a/mozilla/xpcom/io/nsFileSpecMac.cpp b/mozilla/xpcom/io/nsFileSpecMac.cpp index d8bd5f45b27..d92624bd669 100644 --- a/mozilla/xpcom/io/nsFileSpecMac.cpp +++ b/mozilla/xpcom/io/nsFileSpecMac.cpp @@ -21,6 +21,7 @@ #include "FullPath.h" #include "FileCopy.h" +#include "MoreFilesExtras.h" #include "nsEscape.h" #include @@ -39,14 +40,16 @@ namespace MacFileHelpers memcpy(dst, src, 1 + src[0]); } - void PLstrcpy(Str255 dst, const char* src, int inMaxLen); + void PLstrcpy(Str255 dst, const char* src, int inMaxLen=255); + void PLstrncpy(Str255 dst, const char* src, int inMaxLen); void SwapSlashColon(char * s); OSErr FSSpecFromFullUnixPath( const char * unixPath, FSSpec& outSpec, Boolean resolveAlias, - Boolean allowPartial = false); + Boolean allowPartial = false, + Boolean createDirs = false); char* MacPathFromUnixPath(const char* unixPath); char* EncodeMacPath( char* inPath, // NOT const - gets clobbered @@ -54,7 +57,8 @@ namespace MacFileHelpers Boolean doEscape ); OSErr FSSpecFromPathname( const char* inPathNamePtr, - FSSpec& outSpec); + FSSpec& outSpec, + Boolean inCreateDirs); char* PathNameFromFSSpec( const FSSpec& inSpec, Boolean wantLeafName ); @@ -81,7 +85,7 @@ namespace MacFileHelpers //---------------------------------------------------------------------------------------- void MacFileHelpers::PLstrcpy(Str255 dst, const char* src, int inMax) -//======================================================================================== +//---------------------------------------------------------------------------------------- { int srcLength = strlen(src); NS_ASSERTION(srcLength <= inMax, "Oops, string is too long!"); @@ -91,6 +95,17 @@ void MacFileHelpers::PLstrcpy(Str255 dst, const char* src, int inMax) memcpy(&dst[1], src, srcLength); } +//---------------------------------------------------------------------------------------- +void MacFileHelpers::PLstrncpy(Str255 dst, const char* src, int inMax) +//---------------------------------------------------------------------------------------- +{ + int srcLength = strlen(src); + if (srcLength > inMax) + srcLength = inMax; + dst[0] = srcLength; + memcpy(&dst[1], src, srcLength); +} + //----------------------------------- void MacFileHelpers::SwapSlashColon(char * s) //----------------------------------- @@ -218,7 +233,10 @@ char* MacFileHelpers::MacPathFromUnixPath(const char* unixPath) } // MacFileHelpers::MacPathFromUnixPath //---------------------------------------------------------------------------------------- -OSErr MacFileHelpers::FSSpecFromPathname(const char* inPathNamePtr, FSSpec& outSpec) +OSErr MacFileHelpers::FSSpecFromPathname( + const char* inPathNamePtr, + FSSpec& outSpec, + Boolean inCreateDirs) // FSSpecFromPathname reverses PathNameFromFSSpec. // It returns a FSSpec given a c string which is a mac pathname. //---------------------------------------------------------------------------------------- @@ -226,22 +244,55 @@ OSErr MacFileHelpers::FSSpecFromPathname(const char* inPathNamePtr, FSSpec& outS OSErr err; // Simplify this routine to use FSMakeFSSpec if length < 255. Otherwise use the MoreFiles // routine FSpLocationFromFullPath, which allocates memory, to handle longer pathnames. - if (strlen(inPathNamePtr) < 255) + + size_t inLength = strlen(inPathNamePtr); + if (inLength < 255) { - Str255 path; - - int pos = 0; - while ( (path[++pos] = *inPathNamePtr++) != 0 ) - ; - path[0] = pos-1; // save the length of the string (pos is the next open spot) - - err = ::FSMakeFSSpec(0, 0, path, &outSpec); + Str255 ppath; + MacFileHelpers::PLstrcpy(ppath, inPathNamePtr); + err = ::FSMakeFSSpec(0, 0, ppath, &outSpec); } else - err = FSpLocationFromFullPath(strlen(inPathNamePtr), inPathNamePtr, &outSpec); + err = FSpLocationFromFullPath(inLength, inPathNamePtr, &outSpec); + if (err == dirNFErr && inCreateDirs) + { + const char* path = inPathNamePtr; + outSpec.vRefNum = 0; + outSpec.parID = 0; + do { + // Locate the colon that terminates the node. + // But if we've a partial path (starting with a colon), find the second one. + const char* nextColon = strchr(path + (*path == ':'), ':'); + // Well, if there are no more colons, point to the end of the string. + if (!nextColon) + nextColon = path + strlen(path); + + // Make a pascal string out of this node. Include initial + // and final colon, if any! + Str255 ppath; + MacFileHelpers::PLstrncpy(ppath, path, nextColon - path + 1); + + // Use this string as a relative path using the directory created + // on the previous round (or directory 0,0 on the first round). + err = ::FSMakeFSSpec(outSpec.vRefNum, outSpec.parID, ppath, &outSpec); + + // If this was the leaf node, then we are done. + if (!*nextColon) + break; + + // If we got "file not found", then + // we need to create a directory. + if (err == fnfErr && *nextColon) + err = FSpDirCreate(&outSpec, smCurrentScript, &outSpec.parID); + // For some reason, this usually returns fnfErr, even though it works. + if (err != noErr && err != fnfErr) + return err; + path = nextColon; // next round + } while (1); + } return err; -} +} // MacFileHelpers::FSSpecFromPathname //---------------------------------------------------------------------------------------- OSErr MacFileHelpers::CreateFolderInFolder( @@ -320,7 +371,8 @@ OSErr MacFileHelpers::FSSpecFromFullUnixPath( const char * unixPath, FSSpec& outSpec, Boolean resolveAlias, - Boolean allowPartial) + Boolean allowPartial, + Boolean createDirs) // File spec from URL. Reverses GetURLFromFileSpec // Its input is only the part of the URL // JRM 97/01/08 changed this so that if it's a partial path (doesn't start with '/'), @@ -338,7 +390,7 @@ OSErr MacFileHelpers::FSSpecFromFullUnixPath( { NS_ASSERTION(*unixPath == '/' /*full path*/, "Not a full Unix path!"); } - err = FSSpecFromPathname(macPath, outSpec); + err = FSSpecFromPathname(macPath, outSpec, createDirs); if (err == fnfErr) err = noErr; Boolean dummy; @@ -468,11 +520,12 @@ nsNativeFileSpec::nsNativeFileSpec(const nsNativeFileSpec& inSpec) } //---------------------------------------------------------------------------------------- -nsNativeFileSpec::nsNativeFileSpec(const char* inString) +nsNativeFileSpec::nsNativeFileSpec(const char* inString, bool inCreateDirs) //---------------------------------------------------------------------------------------- { - mError = MacFileHelpers::FSSpecFromFullUnixPath(inString, mSpec, true, true); - // allow a partial path + mError = MacFileHelpers::FSSpecFromFullUnixPath( + inString, mSpec, true, true, inCreateDirs); + // allow a partial path, create as necessary if (mError == fnfErr) mError = noErr; } // nsNativeFileSpec::nsNativeFileSpec @@ -537,9 +590,13 @@ bool nsNativeFileSpec::Exists() const //---------------------------------------------------------------------------------------- void nsNativeFileSpec::SetLeafName(const char* inLeafName) +// In leaf name can actually be a partial path... //---------------------------------------------------------------------------------------- { - MacFileHelpers::PLstrcpy(mSpec.name, inLeafName, nsFileSpecHelpers::kMaxFilenameLength); + // what about long relative paths? Hmm? + Str255 partialPath; + MacFileHelpers::PLstrcpy(partialPath, inLeafName); + mError = FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, partialPath, &mSpec); } // nsNativeFileSpec::SetLeafName //---------------------------------------------------------------------------------------- @@ -579,10 +636,86 @@ void nsNativeFileSpec::ResolveAlias(bool& wasAliased) wasAliased = (wasAliased2 != false); } // nsNativeFileSpec::ResolveAlias +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + long dirID; + Boolean isDirectory; + return (noErr == FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && !isDirectory); +} // nsNativeFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + long dirID; + Boolean isDirectory; + return (noErr == FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && isDirectory); +} // nsNativeFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::GetParent(nsNativeFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + if (mError == noErr) + outSpec.mError = FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, NULL, outSpec); +} // nsNativeFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + long dirID; + Boolean isDirectory; + mError = FSpGetDirectoryID(&mSpec, &dirID, &isDirectory); + if (mError == noErr && isDirectory) + { + mError = FSMakeFSSpec(mSpec.vRefNum, dirID, "\pG'day", *this); + if (mError == noErr) + SetLeafName(inRelativePath); + } +} // nsNativeFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::CreateDirectory(int /* unix mode */) +//---------------------------------------------------------------------------------------- +{ + long ignoredDirID; + FSpDirCreate(&mSpec, smCurrentScript, &ignoredDirID); +} // nsNativeFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::Delete(bool inRecursive) +//---------------------------------------------------------------------------------------- +{ + if (inRecursive) + { + // MoreFilesExtras + mError = DeleteDirectory( + mSpec.vRefNum, + mSpec.parID, + const_cast(mSpec.name)); + } + else + mError = FSpDelete(&mSpec); +} // nsNativeFileSpec::Delete + + //======================================================================================== // Macintosh nsFilePath implementation //======================================================================================== +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const char* inString, bool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mPath(nsnull) +, mNativeFileSpec(inString, inCreateDirs) +{ + // Make canonical and absolute. + char * path = MacFileHelpers::PathNameFromFSSpec( mNativeFileSpec, TRUE ); + mPath = MacFileHelpers::EncodeMacPath(path, true, true); +} //---------------------------------------------------------------------------------------- nsFilePath::nsFilePath(const nsNativeFileSpec& inSpec) //---------------------------------------------------------------------------------------- @@ -601,3 +734,118 @@ void nsFilePath::operator = (const nsNativeFileSpec& inSpec) mPath = MacFileHelpers::EncodeMacPath(path, true, true); mNativeFileSpec = inSpec; } // nsFilePath::operator = + +//======================================================================================== +// nsFileURL implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const char* inString, bool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mURL(nsnull) +, mNativeFileSpec(inString + kFileURLPrefixLength, inCreateDirs) +{ + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + // Make canonical and absolute. + char* path = MacFileHelpers::PathNameFromFSSpec( mNativeFileSpec, TRUE ); + char* escapedPath = MacFileHelpers::EncodeMacPath(path, true, true); + mURL = nsFileSpecHelpers::StringDup(kFileURLPrefix, kFileURLPrefixLength + strlen(escapedPath)); + strcat(mURL, escapedPath); + delete [] escapedPath; +} // nsFileURL::nsFileURL + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator( + const nsNativeFileSpec& inDirectory +, int inIterateDirection) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mExists(false) + , mIndex(-1) +{ + CInfoPBRec pb; + DirInfo* dipb = (DirInfo*)&pb; + // Sorry about this, there seems to be a bug in CWPro 4: + const FSSpec& inSpec = inDirectory.nsNativeFileSpec::operator const FSSpec&(); + Str255 outName; + MacFileHelpers::PLstrcpy(outName, inSpec.name); + pb.hFileInfo.ioNamePtr = outName; + pb.hFileInfo.ioVRefNum = inSpec.vRefNum; + pb.hFileInfo.ioDirID = inSpec.parID; + pb.hFileInfo.ioFDirIndex = 0; // use ioNamePtr and ioDirID + + OSErr err = PBGetCatInfoSync( &pb ); + + // test that we have got a directory back, not a file + if ( (err != noErr ) || !( dipb->ioFlAttrib & 0x0010 ) ) + return; + // Sorry about this, there seems to be a bug in CWPro 4: + FSSpec& currentSpec = mCurrent.nsNativeFileSpec::operator FSSpec&(); + currentSpec.vRefNum = inSpec.vRefNum; + currentSpec.parID = dipb->ioDrDirID; + mMaxIndex = pb.dirInfo.ioDrNmFls; + if (inIterateDirection > 0) + { + mIndex = 0; // ready to increment + ++(*this); // the pre-increment operator + } + else + { + mIndex = mMaxIndex + 1; // ready to decrement + --(*this); // the pre-decrement operator + } +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +OSErr nsDirectoryIterator::SetToIndex() +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec cipb; + DirInfo *dipb=(DirInfo *)&cipb; + Str255 objectName; + dipb->ioCompletion = NULL; + dipb->ioFDirIndex = mIndex; + // Sorry about this, there seems to be a bug in CWPro 4: + FSSpec& currentSpec = mCurrent.nsNativeFileSpec::operator FSSpec&(); + dipb->ioVRefNum = currentSpec.vRefNum; /* Might need to use vRefNum, not sure*/ + dipb->ioDrDirID = currentSpec.parID; + dipb->ioNamePtr = objectName; + OSErr err = PBGetCatInfoSync(&cipb); + if (err == noErr) + err = FSMakeFSSpec(currentSpec.vRefNum, currentSpec.parID, objectName, ¤tSpec); + mExists = err == noErr; + return err; +} // nsDirectoryIterator::SetToIndex() + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + mExists = false; + while (--mIndex > 0) + { + OSErr err = SetToIndex(); + if (err == noErr) + break; + } + return *this; +} // nsDirectoryIterator::operator -- + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = false; + if (mIndex >= 0) // probably trying to use a file as a directory! + while (++mIndex <= mMaxIndex) + { + OSErr err = SetToIndex(); + if (err == noErr) + break; + } + return *this; +} // nsDirectoryIterator::operator ++ diff --git a/mozilla/xpcom/io/nsFileSpecUnix.cpp b/mozilla/xpcom/io/nsFileSpecUnix.cpp index 357ee8d1ed6..26ecae33505 100644 --- a/mozilla/xpcom/io/nsFileSpecUnix.cpp +++ b/mozilla/xpcom/io/nsFileSpecUnix.cpp @@ -16,27 +16,205 @@ * Reserved. */ -// This file is included by nsFileSpec.cpp, and includes the Unix-specific -// implementations. +// This file is included by nsFileSpec.cpp, and includes the Unix-specific +// implementations. + +#include +#include +#include +#include +#include +#include + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(char*& ioPath, bool inMakeDirs) +// Canonify, make absolute, and check whether directories exist +//---------------------------------------------------------------------------------------- +{ + if (!ioPath) + return; + if (inMakeDirs) + { + const mode_t mode = 0700; + nsFileSpecHelpers::MakeAllDirectories(ioPath, mode); + } + char buffer[MAXPATHLEN]; + errno = 0; + *buffer = '\0'; + char* canonicalPath = realpath(ioPath, buffer); + if (!canonicalPath) + { + // Linux's realpath() is pathetically buggy. If the reason for the nil + // result is just that the leaf does not exist, strip the leaf off, + // process that, and then add the leaf back. + char* allButLeaf = nsFileSpecHelpers::StringDup(ioPath); + if (!allButLeaf) + return; + char* lastSeparator = strrchr(allButLeaf, '/'); + if (lastSeparator) + { + *lastSeparator = '\0'; + canonicalPath = realpath(allButLeaf, buffer); + strcat(buffer, "/"); + // Add back the leaf + strcat(buffer, ++lastSeparator); + } + delete [] allButLeaf; + } + if (!canonicalPath && *ioPath != '/' && !inMakeDirs) + { + // Well, if it's a relative path, hack it ourselves. + canonicalPath = realpath(".", buffer); + if (canonicalPath) + { + strcat(canonicalPath, "/"); + strcat(canonicalPath, ioPath); + } + } + if (canonicalPath) + nsFileSpecHelpers::StringAssign(ioPath, canonicalPath); +} // nsFileSpecHelpers::Canonify //---------------------------------------------------------------------------------------- void nsNativeFileSpec::SetLeafName(const char* inLeafName) //---------------------------------------------------------------------------------------- { - nsFileSpecHelpers::LeafReplace(mPath, '/', inLeafName); + nsFileSpecHelpers::LeafReplace(mPath, '/', inLeafName); } // nsNativeFileSpec::SetLeafName //---------------------------------------------------------------------------------------- char* nsNativeFileSpec::GetLeafName() const //---------------------------------------------------------------------------------------- { - return nsFileSpecHelpers::GetLeaf(mPath, '/'); + return nsFileSpecHelpers::GetLeaf(mPath, '/'); } // nsNativeFileSpec::GetLeafName //---------------------------------------------------------------------------------------- bool nsNativeFileSpec::Exists() const //---------------------------------------------------------------------------------------- { - return false; // fixme + struct stat st; + return 0 == stat(mPath, &st); } // nsNativeFileSpec::Exists +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return 0 == stat(mPath, &st) && S_ISREG(st.st_mode); +} // nsNativeFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return 0 == stat(mPath, &st) && S_ISDIR(st.st_mode); +} // nsNativeFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::GetParent(nsNativeFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + nsFileSpecHelpers::StringAssign(outSpec.mPath, mPath); + char* cp = strrchr(outSpec.mPath, '/'); + if (cp) + *cp = '\0'; +} // nsNativeFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + if (!inRelativePath || !mPath) + return; + + if (mPath[strlen(mPath) - 1] != '/') + char* newPath = nsFileSpecHelpers::ReallocCat(mPath, "/"); + SetLeafName(inRelativePath); +} // nsNativeFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::CreateDirectory(int mode) +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + mkdir(mPath, mode); +} // nsNativeFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::Delete(bool inRecursive) +// To check if this worked, call Exists() afterwards, see? +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this); i; i++) + { + nsNativeFileSpec& child = (nsNativeFileSpec&)i; + child.Delete(inRecursive); + } + } + rmdir(mPath); + } + else + remove(mPath); +} // nsNativeFileSpec::Delete + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator( + const nsNativeFileSpec& inDirectory +, int inIterateDirection) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mDir(nsnull) + , mExists(false) +{ + mCurrent += "sysygy"; // prepare the path for SetLeafName + mDir = opendir((const char*)nsFilePath(inDirectory)); + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ + if (mDir) + closedir(mDir); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = false; + if (!mDir) + return *this; + char* dot = "."; + char* dotdot = ".."; + struct dirent* entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dot) == 0) + entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dotdot) == 0) + entry = readdir(mDir); + if (entry) + { + mExists = true; + mCurrent.SetLeafName(entry->d_name); + } + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- diff --git a/mozilla/xpcom/io/nsFileSpecWin.cpp b/mozilla/xpcom/io/nsFileSpecWin.cpp index d66fe1f457b..a33bd817cf1 100644 --- a/mozilla/xpcom/io/nsFileSpecWin.cpp +++ b/mozilla/xpcom/io/nsFileSpecWin.cpp @@ -19,6 +19,17 @@ // This file is included by nsFileSpec.cp, and includes the Windows-specific // implementations. +#include + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(char*& ioPath, bool inMakeDirs) +// Canonify, make absolute, and check whether directories exist +//---------------------------------------------------------------------------------------- +{ + NS_NOTYETIMPLEMENTED("Please, some Winhead please write this!"); + return ioPath; +} + //---------------------------------------------------------------------------------------- nsNativeFileSpec::nsNativeFileSpec(const nsFilePath& inPath) //---------------------------------------------------------------------------------------- @@ -31,9 +42,17 @@ nsNativeFileSpec::nsNativeFileSpec(const nsFilePath& inPath) void nsNativeFileSpec::operator = (const nsFilePath& inPath) //---------------------------------------------------------------------------------------- { - // Convert '/' to '\' - nsFileSpecHelpers::StringAssign(mPath, (const char*)inPath); - for (char* cp = mPath; *cp; cp++) + // Strip the leading slash, which should + // leave us pointing to a drive letter. + nsFileSpecHelpers::StringAssign(mPath, (const char*)inPath + 1); + + // Convert the vertical slash to a colon + char* cp = mPath + 1; + if (strstr(cp, "|/") == cp) + *cp = ':'; + + // Convert '/' to '\'. + while (*++cp) { if (*cp == '/') *cp = '\\'; @@ -79,6 +98,138 @@ char* nsNativeFileSpec::GetLeafName() const bool nsNativeFileSpec::Exists() const //---------------------------------------------------------------------------------------- { - return false; // fixme + struct stat st; + return 0 == stat(mPath, &st); } // nsNativeFileSpec::Exists +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return 0 == stat(mPath, &st) && S_ISREG(st.st_mode); +} // nsNativeFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return 0 == stat(mPath, &st) && S_ISDIR(st.st_mode); +} // nsNativeFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::GetParent(nsNativeFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + nsFileSpecHelpers::StringAssign(outSpec.mPath, mPath); + char* cp = strrchr(outSpec.mPath, '\\'); + if (cp) + *cp = '\0'; +} // nsNativeFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + if (!inRelativePath || !mPath) + return; + + if (mPath[strlen(mPath) - 1] != '\\') + char* newPath = nsFileSpecHelpers::ReallocCat(mPath, "\\"); + SetLeafName(inRelativePath); +} // nsNativeFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::CreateDirectory() +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + NS_NOTYETIMPLEMENTED("Please, some Winhead please fix this!"); + mkdir(mPath, mode); +} // nsNativeFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::Delete(bool inRecursive) +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this); i; i++) + { + const nsNativeFileSpec& child = (nsNativeFileSpec&)i; + child.Delete(inRecursive); + } + } + NS_NOTYETIMPLEMENTED("Please, some Winhead please fix this!"); + rmdir(mPath); + } + else + { + NS_NOTYETIMPLEMENTED("Please, some Winhead please write this!"); + remove(mPath); + } +} // nsNativeFileSpec::Delete + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator( + const nsNativeFileSpec& inDirectory +, int inIterateDirection) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) +#if 0 // Some kind winhead please build, test, and remove when ready. + , mDir(nsnull) +#endif // XP_PC -- ifdef to be removed. + , mExists(false) +{ +NS_NOTYETIMPLEMENTED("Please, some kind Winhead please check this!"); + mCurrent += "foo"; +#if 0 // Some kind winhead please build, test, and remove when ready. + mDir = opendir(mPath); +#endif // XP_PC -- ifdef to be removed. + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ +NS_NOTYETIMPLEMENTED("Please, some kind Winhead please check this!"); +#if 0 // Some kind winhead please build, test, and remove when ready. + if (mDir) + closedir(mDir); +#endif // XP_PC -- ifdef to be removed. +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = false; +NS_NOTYETIMPLEMENTED("Please, some kind Winhead please check this!"); +#if 0 // Some kind winhead please build, test, and remove when ready. + if (!mDir) + return *this; + struct dirent* entry = readdir(mDir); + if (entry) + { + mExists = true; + mCurrent.SetLeafName(entry->d_name); + } +#endif // XP_PC -- ifdef to be removed. + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- + diff --git a/mozilla/xpcom/tests/FilesTest.cpp b/mozilla/xpcom/tests/FilesTest.cpp index 31e09e909b3..c134764a0bd 100644 --- a/mozilla/xpcom/tests/FilesTest.cpp +++ b/mozilla/xpcom/tests/FilesTest.cpp @@ -11,7 +11,7 @@ void FilesTest::WriteStuff(nsOutputFileStream& s) //---------------------------------------------------------------------------------------- { // Initialize a URL from a string without suffix. Change the path to suit your machine. - nsFileURL fileURL("file:///Development/MPW/MPW%20Shell"); + nsFileURL fileURL("file:///Development/MPW/MPW%20Shell", false); s << "File URL initialized to: \"" << fileURL << "\""<< nsEndl; // Initialize a Unix path from a URL @@ -44,7 +44,7 @@ void FilesTest::WriteStuff(nsOutputFileStream& s) } // WriteStuff //---------------------------------------------------------------------------------------- -void main() +int main() // For use with DEBUG defined. //---------------------------------------------------------------------------------------- { @@ -59,38 +59,59 @@ void main() FilesTest::WriteStuff(nsOut); nsOut << nsEndl << nsEndl; - // Test of nsOutputFileStream - - nsFilePath myTextFilePath("iotest.txt"); + // - Test of nsOutputFileStream + nsFilePath myTextFilePath("mumble/iotest.txt", true); // relative path. + const char* pathAsString = (const char*)myTextFilePath; + if (*pathAsString != '/') { - nsOut << "WRITING IDENTICAL OUTPUT TO " << (const char*)myTextFilePath << nsEndl << nsEndl; + nsOut + << "ERROR: after initializing the path object with a relative path," + << "\n the path consisted of the string " + << "\n\t" << pathAsString + << "\n which is not a canonical full path!" + << nsEndl; + return -1; + } + + nsNativeFileSpec mySpec(myTextFilePath); + { + nsOut << "WRITING IDENTICAL OUTPUT TO " << pathAsString << nsEndl << nsEndl; nsOutputFileStream testStream(myTextFilePath); if (!testStream.is_open()) { nsOut << "ERROR: File " - << (const char*)myTextFilePath + << pathAsString << " could not be opened for output" << nsEndl; - return; + return -1; } FilesTest::WriteStuff(testStream); } // <-- Scope closes the stream (and the file). - // Test of nsInputFileStream + if (!mySpec.Exists() || mySpec.IsDirectory() || !mySpec.IsFile()) + { + nsOut + << "ERROR: File " + << pathAsString + << " is not a file (cela n'est pas un pipe)" + << nsEndl; + return -1; + } + // - Test of nsInputFileStream { - nsOut << "READING BACK DATA FROM " << (const char*)myTextFilePath << nsEndl << nsEndl; + nsOut << "READING BACK DATA FROM " << pathAsString << nsEndl << nsEndl; nsInputFileStream testStream2(myTextFilePath); if (!testStream2.is_open()) { nsOut << "ERROR: File " - << (const char*)myTextFilePath + << pathAsString << " could not be opened for input" << nsEndl; - return; + return -1; } char line[1000]; @@ -101,4 +122,101 @@ void main() nsOut << line << nsEndl; } } // <-- Scope closes the stream (and the file). + + // - Test of GetParent() + + nsNativeFileSpec parent; + mySpec.GetParent(parent); + nsFilePath parentPath(parent); + nsOut + << "GetParent() on " + << "\n\t" << pathAsString + << "\n yields " + << "\n\t" << (const char*)parentPath + << nsEndl; + + // - Test of non-recursive delete + + nsOut + << "Attempting to delete " + << "\n\t" << (const char*)parentPath + << "\n without recursive option (should fail)" + << nsEndl; + parent.Delete(false); + if (parent.Exists()) + nsOut << "Test passed." << nsEndl; + else + { + nsOut + << "ERROR: File " + << "\n\t" << (const char*)parentPath + << "\n has been deleted without the recursion option," + << "\n and is a nonempty directory!" + << nsEndl; + return -1; + } + + // - Test of recursive delete + + nsOut + << "Deleting " + << "\n\t" << (const char*)parentPath + << "\n with recursive option" + << nsEndl; + parent.Delete(true); + if (parent.Exists()) + { + nsOut + << "ERROR: Directory " + << "\n\t" << (const char*)parentPath + << "\n has NOT been deleted despite the recursion option!" + << nsEndl; + return -1; + } + else + nsOut << "Test passed." << nsEndl; + + // - Test of CreateDirectory + + nsOut + << "Testing CreateDirectory() using" + << "\n\t" << (const char*)parentPath + << nsEndl; + + parent.CreateDirectory(); + if (parent.Exists()) + nsOut << "Test passed." << nsEndl; + else + { + nsOut << "ERROR: Test failed." << nsEndl; + return -1; + } + parent.Delete(true); + +#ifndef XP_PC // uncomment when tested and ready. + + // - Test of directory iterator + + nsNativeFileSpec grandparent; + parent.GetParent(grandparent); // should be the original default directory. + nsFilePath grandparentPath(grandparent); + + nsOut << "Forwards listing of " << (const char*)grandparentPath << ":" << nsEndl; + for (nsDirectoryIterator i(grandparent, +1); i; i++) + { + char* itemName = ((nsNativeFileSpec&)i).GetLeafName(); + nsOut << '\t' << itemName << nsEndl; + delete [] itemName; + } + + nsOut << "Backwards listing of " << (const char*)grandparentPath << ":" << nsEndl; + for (nsDirectoryIterator i(grandparent, -1); i; i--) + { + char* itemName = ((nsNativeFileSpec&)i).GetLeafName(); + nsOut << '\t' << itemName << nsEndl; + delete [] itemName; + } +#endif + + return 0; } // main