//  This may look like C code, but it is really -*- C++ -*-

//  ------------------------------------------------------------------
//  The Goldware Library
//  Copyright (C) 1990-1999 Odinn Sorensen
//  Copyright (C) 1999-2000 Alexander S. Aganichev
//  ------------------------------------------------------------------
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this program; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//  MA 02111-1307, USA
//  ------------------------------------------------------------------
//  $Id$
//  ------------------------------------------------------------------
//  File utility functions
//  ------------------------------------------------------------------

#include <gfilutil.h>
#ifndef __HAVE_DRIVES__
    #include <pwd.h>
#endif
#ifdef __WIN32__
    #include <windows.h>
#endif
#include <stdlib.h>
#include <string.h>

//  ------------------------------------------------------------------
//  Adds the directory-delimiter character into end of string ('\\' in DOS-based, '/' in unix-based OS)
// Replace wrong directory-delimiter character with good.

std::string& AddBackslash(std::string& p)
{

    for(size_t posn = 0; (posn=p.find(GOLD_WRONG_SLASH_CHR, posn)) != p.npos; posn++)
        p[posn] = GOLD_SLASH_CHR;
    if(p[p.length()-1] != GOLD_SLASH_CHR)
        p += GOLD_SLASH_STR;

    return p;
}

//  ------------------------------------------------------------------
//  Remove one trailing directory-delimiter character ('\\' in DOS-based, '/' in unix-based OS)

std::string& StripBackslash(std::string& p)
{

    std::string::iterator pend = p.end();

    if(isslash(*pend))
        p.erase(pend);

    return p;
}

//  ------------------------------------------------------------------
//  Get size of file. Return values:
// positive number or zero - size of file,
// negative number - error (and error code is stored in errno)

long GetFilesize(const std::string& filename)
{

    if(filename.empty())
    {
        errno = EINVAL;
        return -1;
    }

    struct stat info;
    if(stat(filename.c_str(), &info) == 0)
        return info.st_size;
    return -1;
}

//  ------------------------------------------------------------------
//  Add path to filename, if no path is set. Don't chech size of 'path', be careful!

void MakePathname(std::string& pathname, const std::string& path, const std::string& name)
{

    Path pn;
    MakePathname(pn, path.c_str(), name.c_str());
    pathname = pn;
}


//  ------------------------------------------------------------------
//  Copy pathname with enviroment variables substitution and adds directory delimiter char.
//  Copy not more sizeof(Path) characters (__dst should be type "Path" or equvalence, size is GMAXPATH)

void PathCopy(std::string& dst, const char* src)
{

    dst = src;
    strschg_environ(dst);
    AddBackslash(dst);
}
void PathCopy(std::string& dst, const std::string& src)
{

    dst = src;
    strschg_environ(dst);
    AddBackslash(dst);
}


//  ------------------------------------------------------------------
//  DOS-style enviroment variables substitution in string.
//  In unix-like enviroment also tilde substitution in string.

int strschg_environ(std::string& s)
{

    std::string fnd;
    int replaced = 0;
    size_t posn, posn1;

    if (s.length() > 1)
    {
        while(((posn=s.find('%')) != s.npos) and ((posn1=s.find('%', posn+1)) != s.npos))
        {
            fnd = s.substr(posn+1, posn1-1-posn);
            const char* rep = getenv(fnd.c_str());
            rep = rep ? rep : "";
            s.replace(posn, posn1-posn+1, rep);
            replaced++;
        }
    }

#ifndef __HAVE_DRIVES__
    if( s[0] == '~' )
    {
        struct passwd *pe=NULL;
        size_t slash = 1;

        if( (s.length() > 1) and not isslash(s[1]) )
        {
            slash = s.find_first_of(GOLD_SLASH_STR GOLD_WRONG_SLASH_STR, 1);
            fnd.assign(s,1,slash-1);
            pe = getpwnam(fnd.c_str());
        }
        else
        {
            pe = getpwuid(getuid());
        }
        if(pe != NULL)
        {
            fnd.assign(pe->pw_dir);
            if ( slash != std::string::npos )
                fnd += s.substr(slash);
            s=fnd;
            replaced++;
        }
    }
#endif

    return replaced;
}


//  ------------------------------------------------------------------
//  Change dirname to real full pathname

bool maketruepath(std::string &dirname)
{

    bool ok = true;
    std::string ndirname;
    char cwd[GMAXPATH];
    getcwd(cwd, GMAXPATH);
#ifdef __HAVE_DRIVES__
#ifdef __WIN32__
    char expanded[GMAXPATH];
    char *k;
    if(GetFullPathName(dirname.c_str(), GMAXPATH, expanded, &k) == 0)
    {
        dirname = cwd;
        ok = false;
    }
    else
    {
        if(access(expanded, R_OK) == 0)
            dirname = expanded;
        else
        {
            dirname = cwd;
            ok = false;
        }
    }
#elif defined __OS2__
    char expanded[GMAXPATH];
    if(_fullpath(expanded, dirname.c_str(), GMAXPATH) == 0)
    {
        if(access(expanded, R_OK) == 0)
            dirname = expanded;
        else
        {
            dirname = cwd;
            ok = false;
        }
    }
    else
    {
        dirname = cwd;
        ok = false;
    }
#elif defined __DJGPP__
    char expanded[GMAXPATH];
    _fixpath(dirname.c_str(), expanded);
    if(access(expanded, R_OK) == 0)
        dirname = expanded;
    else
    {
        dirname = cwd;
        ok = false;
    }
#else
    long inspos = -1;
    if((dirname.length() == 2) and (dirname[1] == ':'))
        inspos = 2;
    else if((dirname.length() < 2) or (dirname[1] != ':') or isslash(dirname[0]))
        inspos = 0;
    else if(not isslash(dirname[2]))
        inspos = 2;
    if(inspos != -1)
    {
        char chdrive[] = " :";
        chdrive[0] = (inspos == 2) ? dirname[0] : cwd[0];
        if(not chdir(chdrive))
        {
            char dwd[GMAXPATH];
            getcwd(dwd, GMAXPATH);
            if(isslash(dirname[0]))
                ndirname = chdrive;
            else
            {
                ndirname = dwd;
                ndirname += GOLD_SLASH_CHR;
            }
            ndirname += dirname.c_str() + inspos;
            dirname = ndirname;
        }
        else
        {
            dirname = cwd;
            ok = false;
        }
        chdir(cwd);
    }
#endif
#else
    if(not dirname.empty() and (dirname[0] == '~'))
    {
        char* lname;
        const char *p = dirname.c_str()+1;
        if((dirname.length() != 1) and not isslash(*p))
        {
            while(*p and not isslash(*p))
                ndirname += *p++; // get user name
        }
        else
        {
            if ((lname = getlogin()) == NULL)
                lname = getenv("LOGNAME");
            ndirname = lname; // get current user name
        }
        struct passwd *pe = getpwnam(ndirname.c_str()); // get home
        if(pe != NULL)
        {
            ndirname = pe->pw_dir;
            ndirname += GOLD_SLASH_CHR;
            if(isslash(*p))
                ++p;
            ndirname += p;
            dirname = ndirname;
        }
        else
        {
            dirname = cwd;
            ok = false;
        }
    }
    else if(not dirname.empty() and not isslash(dirname[0]))
    {
        ndirname = cwd;
        ndirname += GOLD_SLASH_CHR;
        ndirname += dirname;
        dirname = ndirname;
    }
#endif
    size_t posn;
    for(posn = 0; (posn=dirname.find(GOLD_WRONG_SLASH_CHR, posn)) != dirname.npos; posn++)
        dirname[posn] = GOLD_SLASH_CHR;
    size_t skipfrom, skipto;
#ifdef __HAVE_DRIVES__ /* Prevent from destroying UNC names */
    if(dirname.length() > 1)
    {
        while((skipfrom=dirname.find("\\\\", 1)) != dirname.npos)
            dirname.erase(skipfrom, 1);
    }
#endif
    size_t len = dirname.length();
#ifdef __HAVE_DRIVES__
    while((len > 3) and isslash(dirname[--len]))
#else
    while((len > 1) and isslash(dirname[--len]))
#endif
        dirname.erase(len, 1);
    if(access(dirname.c_str(), R_OK))
    {
        dirname = cwd;
        ok = false;
    }
#ifdef __HAVE_DRIVES__
    if((dirname.length() > 2) and (dirname[0] == '\\') and (dirname[1] == '\\'))
        posn = 2;
    else
#endif
        posn = 0;
    for(; (posn=dirname.find('\\', posn)) != dirname.npos; posn++)
        dirname[posn] = '/';
    while((skipto=dirname.find("/../")) != dirname.npos)
    {
        skipfrom = (skipto == 0) ? 0 : dirname.rfind('/', skipto-1);
        skipto += 2;
        dirname.erase(skipfrom, skipto-skipfrom+1);
    }
    while((skipfrom=dirname.find("/./")) != dirname.npos)
        dirname.erase(skipfrom, 2);
    len = dirname.length();
    if(len > 2 and not strcmp(&(dirname.c_str()[len-2]), "/."))
        dirname.erase(len-2, 2);
    len = dirname.length();
#ifdef __HAVE_DRIVES__
    if((len > 3) and isslash(dirname[--len]))
#else
    if((len > 1) and isslash(dirname[--len]))
#endif
        dirname.erase(len, 1);
    return ok;
}


//  ------------------------------------------------------------------
