You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
9.7 KiB
300 lines
9.7 KiB
//Author: Max Howell <max.howell@methylblue.com>, (C) 2004
|
|
//Copyright: See COPYING file that comes with this distribution
|
|
|
|
#ifndef FILETREE_H
|
|
#define FILETREE_H
|
|
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <tdeio/global.h>
|
|
|
|
//TODO these are pointlessly general purpose now, make them incredibly specific
|
|
|
|
|
|
|
|
typedef TDEIO::filesize_t FileSize;
|
|
|
|
template <class T> class Iterator;
|
|
template <class T> class ConstIterator;
|
|
template <class T> class Chain;
|
|
|
|
template <class T>
|
|
class Link
|
|
{
|
|
public:
|
|
Link( T* const t ) : prev( this ), next( this ), data( t ) {}
|
|
Link() : prev( this ), next( this ), data( 0 ) {}
|
|
|
|
//TODO unlinking is slow and you don't use it very much in this context.
|
|
// ** Perhaps you can make a faster deletion system that doesn't bother tidying up first
|
|
// ** and then you MUST call some kind of detach() function when you remove elements otherwise
|
|
~Link() { delete data; unlink(); }
|
|
|
|
friend class Iterator<T>;
|
|
friend class ConstIterator<T>;
|
|
friend class Chain<T>;
|
|
|
|
private:
|
|
void unlink() { prev->next = next; next->prev = prev; prev = next = this; }
|
|
|
|
Link<T>* prev;
|
|
Link<T>* next;
|
|
|
|
T* data; //ensure only iterators have access to this
|
|
};
|
|
|
|
|
|
template <class T>
|
|
class Iterator
|
|
{
|
|
public:
|
|
Iterator() : link( 0 ) { } //**** remove this, remove this REMOVE THIS!!! dangerous as your implementation doesn't test for null links, always assumes they can be derefenced
|
|
Iterator( Link<T> *p ) : link( p ) { }
|
|
|
|
bool operator==( const Iterator<T>& it ) const { return link == it.link; }
|
|
bool operator!=( const Iterator<T>& it ) const { return link != it.link; }
|
|
bool operator!=( const Link<T> *p ) const { return p != link; }
|
|
|
|
//here we have a choice, really I should make two classes one const the other not
|
|
const T* operator*() const { return link->data; }
|
|
T* operator*() { return link->data; }
|
|
|
|
Iterator<T>& operator++() { link = link->next; return *this; } //**** does it waste time returning in places where we don't use the retval?
|
|
|
|
bool isNull() const { return (link == 0); } //REMOVE WITH ABOVE REMOVAL you don't want null iterators to be possible
|
|
|
|
void transferTo( Chain<T> &chain )
|
|
{
|
|
chain.append( remove() );
|
|
}
|
|
|
|
T* const remove() //remove from list, delete Link, data is returned NOT deleted
|
|
{
|
|
T* const d = link->data;
|
|
Link<T>* const p = link->prev;
|
|
|
|
link->data = 0;
|
|
delete link;
|
|
link = p; //make iterator point to previous element, YOU must check this points to an element
|
|
|
|
return d;
|
|
}
|
|
|
|
private:
|
|
Link<T> *link;
|
|
};
|
|
|
|
|
|
template <class T>
|
|
class ConstIterator
|
|
{
|
|
public:
|
|
ConstIterator( Link<T> *p ) : link( p ) { }
|
|
|
|
bool operator==( const Iterator<T>& it ) const { return link == it.link; }
|
|
bool operator!=( const Iterator<T>& it ) const { return link != it.link; }
|
|
bool operator!=( const Link<T> *p ) const { return p != link; }
|
|
|
|
const T* operator*() const { return link->data; }
|
|
|
|
ConstIterator<T>& operator++() { link = link->next; return *this; }
|
|
|
|
private:
|
|
const Link<T> *link;
|
|
};
|
|
|
|
//**** try to make a generic list class and then a brief full list template that inlines
|
|
// thus reducing code bloat
|
|
template <class T>
|
|
class Chain
|
|
{
|
|
public:
|
|
Chain() { }
|
|
virtual ~Chain() { empty(); }
|
|
|
|
void append( T* const data )
|
|
{
|
|
Link<T>* const link = new Link<T>( data );
|
|
|
|
link->prev = head.prev;
|
|
link->next = &head;
|
|
|
|
head.prev->next = link;
|
|
head.prev = link;
|
|
}
|
|
|
|
void transferTo( Chain &c )
|
|
{
|
|
if( isEmpty() ) return;
|
|
|
|
Link<T>* const first = head.next;
|
|
Link<T>* const last = head.prev;
|
|
|
|
head.unlink();
|
|
|
|
first->prev = c.head.prev;
|
|
c.head.prev->next = first;
|
|
|
|
last->next = &c.head;
|
|
c.head.prev = last;
|
|
}
|
|
|
|
void empty() { while( head.next != &head ) { delete head.next; } }
|
|
|
|
Iterator<T> iterator() const { return Iterator<T>( head.next ); }
|
|
ConstIterator<T> constIterator() const { return ConstIterator<T>( head.next ); }
|
|
const Link<T> *end() const { return &head; }
|
|
bool isEmpty() const { return ( head.next == &head ); }
|
|
|
|
private:
|
|
Link<T> head;
|
|
void operator=( const Chain& ) {}
|
|
};
|
|
|
|
|
|
class Directory;
|
|
class TQString;
|
|
class KURL;
|
|
|
|
class File
|
|
{
|
|
protected:
|
|
Directory *m_parent; //0 if this is treeRoot
|
|
TQString m_name; //< file name
|
|
TQString m_directory;//< the directory of the file
|
|
FileSize m_size; //< size with subdirectories
|
|
FileSize m_ownSize; //< size without subdirectories
|
|
mode_t m_mode; //< file mode
|
|
TQString m_owner; //< file owner name
|
|
TQString m_group; //< file group name
|
|
TQString m_perm; //< file permissions string
|
|
time_t m_time; //< file modification in time_t format
|
|
bool m_symLink; //< true if the file is a symlink
|
|
TQString m_mimeType; //< file mimetype
|
|
bool m_excluded; //< flag if the file is excluded from du
|
|
int m_percent; //< percent flag
|
|
|
|
public:
|
|
File( Directory *parentIn, const TQString &nameIn, const TQString &dir, FileSize sizeIn, mode_t modeIn,
|
|
const TQString &ownerIn, const TQString &groupIn, const TQString &permIn, time_t timeIn, bool symLinkIn,
|
|
const TQString &mimeTypeIn )
|
|
: m_parent( parentIn ), m_name( nameIn ), m_directory( dir ), m_size( sizeIn ), m_ownSize( sizeIn ), m_mode( modeIn ),
|
|
m_owner( ownerIn ), m_group( groupIn ), m_perm( permIn ), m_time( timeIn ), m_symLink( symLinkIn ),
|
|
m_mimeType( mimeTypeIn ), m_excluded( false ), m_percent( -1 ) {}
|
|
|
|
File( const TQString &nameIn, FileSize sizeIn )
|
|
: m_parent( 0 ), m_name( nameIn ), m_directory( TQString() ), m_size( sizeIn ), m_ownSize( sizeIn ), m_mode( 0 ),
|
|
m_owner( TQString() ), m_group( TQString() ), m_perm( TQString() ), m_time( -1 ),
|
|
m_symLink( false ), m_mimeType( TQString() ), m_excluded( false ), m_percent( -1 )
|
|
{
|
|
}
|
|
|
|
virtual ~File() {}
|
|
|
|
inline const TQString & name() const {return m_name;}
|
|
inline const TQString & directory() const {return m_directory;}
|
|
inline const FileSize size() const {return m_excluded ? 0 : m_size;}
|
|
inline const FileSize ownSize() const {return m_excluded ? 0 : m_ownSize;}
|
|
inline const mode_t mode() const {return m_mode;}
|
|
inline const TQString & owner() const {return m_owner;}
|
|
inline const TQString & group() const {return m_group;}
|
|
inline const TQString & perm() const {return m_perm;}
|
|
inline const time_t time() const {return m_time;}
|
|
inline const TQString & mime() const {return m_mimeType;}
|
|
inline const bool isSymLink() const {return m_symLink;}
|
|
virtual const bool isDir() const {return false;}
|
|
inline const bool isExcluded() const {return m_excluded;}
|
|
inline void exclude( bool flag ) {m_excluded = flag;}
|
|
inline const int intPercent() const {return m_percent;}
|
|
inline const TQString percent() const {if( m_percent < 0 )
|
|
return "INV";
|
|
TQString buf;
|
|
buf.sprintf( "%d.%02d%%", m_percent / 100, m_percent % 100 );
|
|
return buf;}
|
|
inline void setPercent( int p ) {m_percent = p;}
|
|
inline const Directory* parent() const {return m_parent;}
|
|
|
|
inline void setSizes( TDEIO::filesize_t totalSize, TDEIO::filesize_t ownSize )
|
|
{
|
|
m_ownSize = ownSize;
|
|
m_size = totalSize;
|
|
}
|
|
|
|
enum UnitPrefix { kilo, mega, giga, tera };
|
|
|
|
static const FileSize DENOMINATOR[4];
|
|
static const char PREFIX[5][2];
|
|
|
|
TQString fullPath( const Directory* = 0 ) const;
|
|
TQString humanReadableSize( UnitPrefix key = mega ) const;
|
|
|
|
static TQString humanReadableSize( FileSize size, UnitPrefix Key = mega );
|
|
|
|
friend class Directory;
|
|
};
|
|
|
|
|
|
//TODO when you modify this to take into account hardlinks you should make the Chain layered not inherited
|
|
class Directory : public Chain<File>, public File
|
|
{
|
|
public:
|
|
Directory( Directory *parentIn, const TQString &nameIn, const TQString &dir, FileSize sizeIn, mode_t modeIn,
|
|
const TQString &ownerIn, const TQString &groupIn, const TQString &permIn, time_t timeIn, bool symLinkIn,
|
|
const TQString &mimeTypeIn )
|
|
: File( parentIn, nameIn, dir, sizeIn, modeIn, ownerIn, groupIn, permIn, timeIn, symLinkIn, mimeTypeIn ),
|
|
m_fileCount( 0 )
|
|
{}
|
|
|
|
Directory( const TQString &name, TQString url ) : File( name, 0 ), m_fileCount( 0 )
|
|
{
|
|
m_directory = url;
|
|
}
|
|
|
|
virtual ~Directory() {}
|
|
virtual const bool isDir() const {return true;}
|
|
|
|
void append( File *p )
|
|
{
|
|
++m_fileCount;
|
|
|
|
Directory *parent = m_parent;
|
|
while( parent )
|
|
{
|
|
parent->m_fileCount++;
|
|
parent = parent->m_parent;
|
|
}
|
|
|
|
Chain<File>::append( p );
|
|
p->m_parent = this;
|
|
}
|
|
|
|
void remove( File *p )
|
|
{
|
|
for( Iterator<File> it = Chain<File>::iterator(); it != Chain<File>::end(); ++it )
|
|
if( (*it) == p )
|
|
{
|
|
--m_fileCount;
|
|
|
|
Directory *parent = m_parent;
|
|
while( parent )
|
|
{
|
|
parent->m_fileCount--;
|
|
parent = parent->m_parent;
|
|
}
|
|
|
|
it.remove();
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint fileCount() const { return m_fileCount; }
|
|
|
|
private:
|
|
Directory( const Directory& );
|
|
void operator=( const Directory& );
|
|
|
|
uint m_fileCount;
|
|
};
|
|
|
|
#endif
|