#include "precomp.h"

#include "gtools.h"

#include "stdarg.h"

#ifdef _WIN32

#include "direct.h"

#else

#include "sys/stat.h"

#include "sys/types.h"

#include "unistd.h"

#endif


PList::PList()
{
    m_pHead = m_pTail = 0;
    m_lCount = 0;
}

PList::~PList()
{
    DeleteContents();
} 

bool PList::DeleteContents()
{
    while( m_pHead )
    {
        PNode* pNext = m_pHead->m_pNext;
        m_pHead->m_pNext = 0;
        delete m_pHead;
        m_pHead = pNext;
    }
    m_pHead = m_pTail = 0;
    m_lCount = 0;
    return true;
} 

bool PList::RemoveContents()
{
    while( m_pHead )
    {
        PNode* pNext = m_pHead->m_pNext;
        m_pHead->m_pNext = m_pHead->m_pPrevious = 0;
        m_pHead = pNext;
    }
    m_pHead = m_pTail = 0;
    m_lCount = 0;
    return  true;
} 

bool PList::Contains( PNode* p )
{
    bool bSuccess = false;
    if( p != 0 )
    {
        for( PNode* q = m_pHead; q; q = q->m_pNext )
        {
            if( q == p )
            {
                bSuccess = true;
                break;
            }
        }
    }
    return bSuccess;
}

bool PList::AddHead( PNode* p )
{
    p->m_pPrevious = 0;
    m_lCount++;

    if( !m_pHead )
    {
        m_pHead = m_pTail = p;
        p->m_pNext = 0;
    }
    else
    {
        p->m_pNext = m_pHead;
        m_pHead->m_pPrevious = p;
        m_pHead = p;
    }
    return true;
}

bool PList::AddTail( PNode* p )
{
    if( !m_pTail )
    {
        m_pHead = m_pTail = p;
        p->m_pNext = 0;
        m_lCount = 1;
    }
    else
    {
        m_lCount++;
        p->m_pNext = 0;
        p->m_pPrevious = m_pTail;
        m_pTail->m_pNext = p;
        m_pTail = p;
    }
    return true;
}

bool PList::InsertBefore( PNode* p, PNode* q )
{
    if( !q )
        return AddTail( p );
    
    if( !q->m_pPrevious )
        return AddHead( p );

    ++m_lCount;
    p->m_pPrevious = q->m_pPrevious;
    p->m_pPrevious->m_pNext = p;
    q->m_pPrevious = p;
    p->m_pNext = q;
    return true;
}

bool PList::InsertAfter( PNode* p, PNode* q )
{
    if( !q )
        return AddHead( p );

    if( !q->m_pNext )
        return AddTail( p );

    return InsertBefore( p, q->m_pNext );
}

void PList::Delete( PNode* p )
{
    Remove( p );
    delete p;
}

void PList::Remove( PNode* p )
{
    m_lCount--;

    if( m_pHead == p )
        m_pHead = p->m_pNext;

    if( m_pTail == p )
        m_pTail = p->m_pPrevious;

    if( p->m_pNext )
        p->m_pNext->m_pPrevious = p->m_pPrevious;

    if( p->m_pPrevious )
        p->m_pPrevious->m_pNext = p->m_pNext;

    p->m_pNext = p->m_pPrevious = 0;
}

bool PList::IsEmpty()
{
    return m_pHead ? true : false;
} 

PNode* PList::Find( long lZeroBasedIndex )
{
    long lIndex = 0;
    for( PNode* p = m_pHead; p; p = p->m_pNext )
        if( lIndex++ == lZeroBasedIndex )
            return p;

    return 0;
} 

bool PList::Merge( PList& s )
{
    while( s.m_pHead )
    {
        PNode* pNode = s.m_pHead;
        s.Remove( s.m_pHead );
        AddTail( pNode );
    }
    return true;
}

// reduce if your crap OS cannot handle tit - it ;(

#define BUFFERSIZE_FOR_SPRINTF    10480


PString::PString()
{
    m_iStringLength = 0;
    m_lpszData = 0;
}

inline void PString::CopyStringData(const char* lpszFrom)
{
    if( lpszFrom )
    {
        m_iStringLength = strlen( lpszFrom )+1;
        if( m_iStringLength < sizeof(m_szFixedBuffer) )
        {
            m_lpszData = m_szFixedBuffer;
            strcpy( m_lpszData, lpszFrom );
        }
        else if( m_iStringLength > 0 )
        {
            m_lpszData = new char[ m_iStringLength ];
            if( m_lpszData != 0 )
                strcpy( m_lpszData, lpszFrom );
            else m_iStringLength = 0;
        }
        else m_lpszData = 0;
    }
    else
    {
        m_lpszData = 0;
        m_iStringLength = 0;
    }
}

inline void PString::DeleteStringData()
{
    if( (m_lpszData != m_szFixedBuffer) && m_lpszData )
        delete m_lpszData;
    m_lpszData = 0;
    m_iStringLength = 0;
}


void PString::Append( const char* pString, unsigned long dwSize )
{
    // *NOT* optimized


    unsigned long dwCombinedLength = m_iStringLength + dwSize;
    if( dwCombinedLength && dwSize )
    {
        char* lpszData = new char[ dwCombinedLength + 2 ];
        if( m_lpszData && m_iStringLength )
            strcpy( lpszData, m_lpszData );
        strncpy( lpszData+m_iStringLength, pString, dwSize );
        lpszData[dwCombinedLength] = 0;
        DeleteStringData();
        CopyStringData(lpszData);
        delete lpszData;
         
    }
}


PString::PString( const char* lpszArgument )
{
    CopyStringData( lpszArgument );
}

PString::PString( const PString& objectSrc )
{
    CopyStringData( objectSrc.m_lpszData );
}

PString::PString( int, const char* szFormat, ... )
{
    if( szFormat )
    {
        char buffer[BUFFERSIZE_FOR_SPRINTF];
        va_list argptr;
        va_start( argptr, szFormat );
        ::vsprintf(buffer,szFormat,argptr);
        buffer[BUFFERSIZE_FOR_SPRINTF-1]=0;
        CopyStringData( buffer );
    }
    else
    {
        m_iStringLength = 0;
        m_lpszData = 0;
    }
}

PString::~PString()
{
    DeleteStringData();
}

void PString::sprintf( const char* szFormat, ... )
{
    DeleteStringData();
    m_lpszData = 0;
    m_iStringLength = 0;
    if( szFormat )
    {
        char buffer[BUFFERSIZE_FOR_SPRINTF];
        va_list argptr;
        va_start( argptr, szFormat );
        ::vsprintf(buffer,szFormat,argptr);
        buffer[BUFFERSIZE_FOR_SPRINTF-1]=0;
        CopyStringData( buffer );
    }
}

void PString::vsprintf( const char* szFormat, va_list args )
{
    DeleteStringData();
    m_lpszData = 0;
    m_iStringLength = 0;
    if( szFormat )
    {
        char buffer[BUFFERSIZE_FOR_SPRINTF];
        ::vsprintf(buffer,szFormat,args);
        buffer[BUFFERSIZE_FOR_SPRINTF-1]=0;
        CopyStringData( buffer );
    }
} 

PString& PString::operator=( const char* objectSrc )
{
    if( objectSrc != m_lpszData )
    {
        DeleteStringData();
        CopyStringData( objectSrc );
    }
    return *this;
}

PString& PString::operator=( PString& objectSrc )
{
    if( this != &objectSrc )
    {
        DeleteStringData();
        CopyStringData( objectSrc.m_lpszData );
    }
    return *this;
}

#ifdef _WIN32

#include "windows.h" 
#else
#include "errno.h"
#endif

PString GetLastErrorString()
{
#ifdef _WIN32

    PString strResult;
    void* lpMsgBuf = NULL;

    if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
        GetLastError(),  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ) && lpMsgBuf )
    {
        strResult = (LPCSTR) lpMsgBuf;
        LocalFree( lpMsgBuf );
        LPSTR p = strResult;
        while( isspace(p[strlen(p)-1]) )
            p[strlen(p)-1] = 0;
    }
    return strResult;
#else

    return PString(strerror(errno));
#endif

}

BOOL ChangeDirectory( LPCSTR lpszDirectory )
{
    if( !lpszDirectory )
        return FALSE;

#ifndef _WIN32

    if( chdir( lpszDirectory ) < 0 )
    {
        return FALSE;
    }
    else
    {
        return TRUE;
    }
#else


    // determine if contains a drive letter

    LPCSTR lpszDrive = strchr( lpszDirectory, ':' );
    if( lpszDrive )
    {
        if( _chdrive( toupper(lpszDrive[-1]) - 'A' + 1 ) == -1 )
        {
            return FALSE;
        }
    }
    return SetCurrentDirectory( lpszDirectory );
#endif

} // ChangeDirectory()



PString GetCurrentDirectory()
{
    char szBuffer[1024];
    *szBuffer = 0;
#ifdef _WIN32

    ::GetCurrentDirectory( sizeof(szBuffer), szBuffer );
#elif defined(TARGET_IS_UNIX)

    getcwd (szBuffer,sizeof(szBuffer));
#endif

    return PString( szBuffer );
} // GetCurrentDirectory()


BOOL MakeSurePathExists( LPCSTR lpszFileName )
{
    char szBuffer[1024];
    strcpy( szBuffer, lpszFileName );

    // if a path is given, change the current drive

    PString strCurrentDirectory( GetCurrentDirectory() );

#ifdef _WIN32

    LPSTR lpszPathSeparator = strchr( lpszFileName, ':' );
    if( lpszPathSeparator )
    {
        CHAR szDrive[] = "?:\\";
        szDrive[0] = lpszPathSeparator[-1];

        // fail if unable to change to drive specified

        if( !ChangeDirectory( szDrive ) )
        {
            return FALSE;
        }
        if( lpszPathSeparator[1] == '\\' )
            lpszPathSeparator += 2;
        else
            lpszPathSeparator += 1;

        strcpy( szBuffer, lpszPathSeparator );
    }
    else
    {
        // check if networkpath is given

        if( lpszFileName[0] == '\\' && lpszFileName[1] == '\\')
        {
            // skip Rechnername

            LPSTR pPath = strchr( lpszFileName+2, '\\');
            if( pPath )
            {
                // skip Freigabename

                pPath = strchr( pPath+1, '\\');
                if( pPath)
                {
                    // this is the path we should check

                    strcpy( szBuffer, pPath);

                    // first change drive

                    *pPath = 0;
                    //PTrace( "PMakeSurePathExists sets current network drive %s", lpszFileName );

                    if( !ChangeDirectory( lpszFileName ) )
                    {
                        return FALSE;
                    }
                    *pPath = '\\';
                }
            }
        }
    }
#endif


    LPSTR lpszReadPosition = szBuffer;
    while( *lpszReadPosition )
    {
        CHAR c = *lpszReadPosition;
        if( (c == '\\') || (c == '/') )
        {
            // check if this partial path exists

            *lpszReadPosition = 0;

            if( *szBuffer )
            {
                #ifdef TARGET_IS_WIN32

                if( !CreateDirectory( szBuffer, 0 )
                {
                    DWORD dwLastError = GetLastError();
                    if( dwLastError != ERROR_ALREADY_EXISTS )
                    {
                        ChangeDirectory( strCurrentDirectory );
                        SetLastError(dwLastError);
                        return FALSE;
                    }
                }
                #elif defined(TARGET_IS_UNIX)

                int result = mkdir( szBuffer, S_IRWXU|S_IRWXG|S_IRWXO );
                #endif

            }
            *lpszReadPosition = SLASH_CHAR;
        }
        lpszReadPosition++;
    }
    if( szBuffer[0] )
    {
        #ifdef _WIN32

        if( !CreateDirectory( szBuffer, 0 ) )
        {
            DWORD dwLastError = GetLastError();
            if( dwLastError != ERROR_ALREADY_EXISTS )
            {
                ChangeDirectory( strCurrentDirectory );
                SetLastError(dwLastError);
				return FALSE;
            }
        }
        #else

        int result = mkdir( szBuffer, S_IRWXU|S_IRWXG|S_IRWXO );
        #endif

    }

    ChangeDirectory( strCurrentDirectory );
	#ifdef _WIN32

    SetLastError(S_OK);
	#endif

    return TRUE;
} // PMakeSurePathExists()




syntax highlighted by Code2HTML, v. 0.9.1