/*
Copyright (C) 2010 Arnaud Champenois arthelion92@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KERNEL_H
#define KERNEL_H
#include <string>
#include <sstream>
#include <iomanip>
#include <strings.h>
#define SIZEOF_ARRAY(a) (sizeof(a)/sizeof(a[0]))
template <class T> inline void swap(T& a,T& b)
{ T c = b; b = a; a = c; }
// Class to manage filename components.
// Manages / and windows \ in directory
class FileNameString
{
public:
inline FileNameString();
inline FileNameString(const char*aPathName);
inline FileNameString(const std::string&aPathName);
inline FileNameString(const FileNameString&aPathName);
inline ~FileNameString();
inline FileNameString& operator =(const FileNameString& aPathName);
inline FileNameString& operator =(const char*aPathName);
inline FileNameString& operator =(const std::string&aPathName);
// Full patch, with an optional prefix number on the filename
inline const char*GetPath(int aFileNumber=0) const;
// Drive letter with ':'
inline void SetDrive(const std::string& aDrive);
inline const char* GetDrive() const;
// Directory path, no trailing slash
inline void SetDirectory(const std::string& aPath);
inline void AppendDirectory(const std::string& aPath);
inline const char*GetDirectory() const;
// Full directory with drive, no trailing slash
inline std::string GetFullDirectory() const;
// FileName with extension
inline void SetFileName(const std::string&aFileName);
inline std::string GetFileName() const;
// BaseFileName without extension
inline void SetBaseFileName(const std::string&aFileName);
inline const char*GetBaseFileName() const;
inline void AppendBaseFileName(const std::string&aString);
inline void PrependBaseFileName(const std::string&aString);
// Extension
inline void SetExtension(const std::string&anExtension);
inline const char*GetExtension() const;
inline bool TestExtension(const char*) const;
inline bool HasExtension() const;
// Is there somethin missing to define the path ?
inline bool IsEmpty() const;
inline int GetNumber() const;
protected:
inline void Split();
inline void SplitFileName();
inline void Merge(int aFileNumber) const;
inline void TransfoToSlash(std::string& aString);
private:
std::string mDrive;
std::string mPath;
std::string mFileName;
std::string mExtension;
mutable std::string mFullName;
};
//====================================
// implementation
FileNameString::FileNameString(const char*aFilename)
{ if(aFilename)
mFullName = aFilename; else mFullName.clear();
Split(); }
FileNameString:: FileNameString() {};
FileNameString::FileNameString(const std::string&aString)
{ mFullName = aString; Split(); }
FileNameString::FileNameString(const FileNameString&aFileName)
{
mFullName = aFileName.mFullName; Split();
}
FileNameString::~FileNameString() {};
FileNameString& FileNameString::operator =(const FileNameString& aFileName)
{ mFullName = aFileName.mFullName; Split(); return *this; }
FileNameString& FileNameString::operator =(const char*aPathName)
{ if(aPathName)
mFullName = aPathName; else mFullName.clear();
Split(); return *this; }
FileNameString& FileNameString::operator =(const std::string&aString)
{ mFullName = aString; Split(); return *this; }
const char*FileNameString::GetPath(int aFileNumber) const
{ if(IsEmpty()) return NULL; Merge(aFileNumber); return mFullName.c_str();}
// Drive
void FileNameString::SetDrive(const std::string& aDrive)
{ mDrive = aDrive; if(!mDrive.empty() && mDrive[mDrive.length()-1] != ':') mDrive += ':'; }
const char*FileNameString::GetDrive() const { return mDrive.c_str(); }
void FileNameString::TransfoToSlash(std::string& aString)
{
#if defined(__WIN32__)
std::string::iterator anIter;
for(anIter = aString.begin(); anIter != aString.end();anIter++)
{ if(*anIter == '\\') *anIter = '/'; }
#endif
}
// Path
void FileNameString::SetDirectory(const std::string& aPath)
{ mPath = aPath;
TransfoToSlash(mPath);
std::string::size_type aDriveIndex;
aDriveIndex = mPath.find(':');
if(aDriveIndex != std::string::npos)
{
mDrive.assign(mPath,0,aDriveIndex);
aDriveIndex++;
std::string aNewPath;
aNewPath.assign(mPath,aDriveIndex,mPath.length());
mPath = aNewPath;
}
int aLength = mPath.length();
while(aLength && mPath[aLength-1] == '/') { mPath.erase(aLength-1); aLength--; }
}
void FileNameString::AppendDirectory(const std::string& aPath)
{
if(aPath.empty()) return;
std::string aNewPath = aPath;
TransfoToSlash(aNewPath);
if(aNewPath[0] != '/')
mPath += '/';
mPath += aNewPath;
}
const char*FileNameString::GetDirectory() const { return mPath.c_str(); }
// Full directory
std::string FileNameString::GetFullDirectory() const
{
std::string aString;
if(!mDrive.empty()) { aString = mDrive; aString += ':'; }
aString += mPath;
return aString;
}
// FileName
void FileNameString::SetFileName(const std::string&aFileName)
{ mFileName = aFileName; SplitFileName(); }
std::string FileNameString::GetFileName() const
{ std::string aString = mFileName; aString += '.'; aString += mExtension; return aString; }
// BaseFileName
void FileNameString::SetBaseFileName(const std::string&aFileName)
{ mFileName = aFileName; }
const char*FileNameString::GetBaseFileName() const { return mFileName.c_str(); }
void FileNameString::AppendBaseFileName(const std::string&aString)
{ mFileName += aString; }
void FileNameString::PrependBaseFileName(const std::string&aString)
{ mFileName = aString+mFileName; }
// Extension
void FileNameString::SetExtension(const std::string&anExtension)
{ if(anExtension.empty()) mExtension.clear();
else
{ if(anExtension[0] == '.') mExtension = anExtension.c_str()+1; else mExtension = anExtension; }
}
const char*FileNameString::GetExtension() const
{ return mExtension.c_str(); }
bool FileNameString::TestExtension(const char*anExtension) const
{ return (strcasecmp(mExtension.c_str(),anExtension) == 0); }
bool FileNameString::HasExtension() const
{ return (!mExtension.empty()); }
bool FileNameString::IsEmpty() const
{ return mFileName.empty(); }
void FileNameString::Split()
{
mDrive.clear(); mPath.clear(); mFileName.clear(); mExtension.clear();
std::string::size_type aDriveIndex,aSlashIndex;
TransfoToSlash(mFullName);
aDriveIndex = mFullName.find(':');
if(aDriveIndex != std::string::npos)
{
mDrive.assign(mFullName,0,aDriveIndex);
aDriveIndex++;
}
else aDriveIndex = 0;
aSlashIndex = mFullName.rfind('/');
if(aSlashIndex != std::string::npos)
{
if(aSlashIndex>aDriveIndex)
{
mPath.assign(mFullName,aDriveIndex,aSlashIndex-aDriveIndex);
size_t aLength = mPath.length();
while(aLength && mPath[aLength-1] == '/') { mPath.erase(aLength-1); aLength--; }
aSlashIndex++;
}
}
else
aSlashIndex = aDriveIndex;
if(aSlashIndex<mFullName.length())
{
mFileName = mFullName.c_str()+aSlashIndex;
SplitFileName();
}
}
void FileNameString::SplitFileName()
{
mExtension.clear();
std::string::size_type aDotIndex;
aDotIndex = mFileName.rfind('.');
if(aDotIndex != std::string::npos)
{
mExtension = mFileName.c_str()+aDotIndex+1;
mFileName.erase(aDotIndex,mFileName.length()-aDotIndex);
}
}
inline int FileNameString::GetNumber() const
{
if(mFileName.empty()) return 0;
std::string aPreNumber;
const char*aPtr = mFileName.c_str();
bool aHasSep = false;
while(*aPtr && (isdigit(*aPtr) || *aPtr == '_' || *aPtr == '-' || *aPtr == ' '))
{
aHasSep = (*aPtr == '_' || *aPtr == '-' || *aPtr == ' ');
aPreNumber += *aPtr;
aPtr++;
}
return atoi(aPreNumber.c_str());
}
void FileNameString::Merge(int aFileNumber) const
{
mFullName.clear();
if(!mDrive.empty())
{
mFullName = mDrive;
mFullName += ':';
}
mFullName += mPath;
if(!mFileName.empty())
{
if(!mPath.empty())
mFullName += '/';
if(aFileNumber>0)
{
std::string aPreNumber;
const char*aPtr = mFileName.c_str();
bool aHasSep = false;
char aSep = '-';
int aCount = 0;
while(*aPtr && (isdigit(*aPtr) || *aPtr == '_' || *aPtr == '-' || *aPtr == ' '))
{
aHasSep = (*aPtr == '_' || *aPtr == '-' || *aPtr == ' ');
if(aHasSep) aSep = *aPtr;
else aCount++;
aPreNumber += *aPtr;
aPtr++;
}
std::ostringstream os;
if(aCount == 0) aCount = 3;
os << std::setw(aCount) << std::setfill('0') << aFileNumber << std::setw(0) << aSep << aPtr;
mFullName += os.str();
}
else
mFullName += mFileName;
}
if(!mExtension.empty())
{
mFullName += '.';
mFullName += mExtension;
}
}
#endif