Subversion Repositories DevTools

Rev

Blame | Last modification | View Log | RSS feed

/***************************************************************************
* Module name   : realpath.c
* Module type   : CMDFILE source file
* Environment(s): n/a
*
* Description:
     realpath resolves all links and references to '.' and
     .' in "file_name" and stores it in "resolved_name".

     It can handle both relative and absolute path names. 
     For absolute path names and relative path whose resolved
     name cannot be expressed relatively (for example,
     ../../reldir), it returns the resolved absolute name.  For
     other relative names, it returns the resolved relative name.

     resolved name must be be big enough (MAXPATHLEN) to
     contain the fully resolved path name.

Returns:
     The realpath function returns the address of the string 
     containing the name of the resolved directory, unless an 
     error occurs, in which case NULL is returned.

*
* Version   Who      Date        Description
            APY      02/03/00    Created
*
* $Source: /cvsroot/device/DEVL/UTILS/CMDFILE/realpath.c,v $            
* $Revision: 1.5 $ $Date: 2004/10/08 03:07:37 $ $State: Exp $ 
* $Author: ayoung $ $Locker:  $
*.........................................................................*/
/*
*     Include Files
*     ---------------
*/
#include <ctype.h>
#include <unistd.h>
#if defined(WIN32)
#include <windows.h>
#endif
#include "cmdfile.h"

const char *        Realpath( const char *name, char *buf );
#if defined(MSDOS)
static void         dos_realpath( const char *in, char *out, char sep );
#endif


int
do_realpath( String_t *str, const char *s )
{
    char name[ PATH_MAX ], buf[ PATH_MAX ];
    int  len;

    if (expected(s++, ',') > 0 &&
            (len = pathargument(s, name, PATH_MAX)) > 0)
    {
        const char *p;

        p = Realpath( name, buf );
        verbose( " realpath(%s) = %s", name, p );
        StringPath( str, p );
        return (1+len);
    }
    return (-1);
}


const char *
Realpath(const char *name, char *buf)
{
#if defined(unix)
    const char *p;

    memset(buf, 0, PATH_MAX);                   /* PURIFY - solaris realpath illuse of 'buf'*/
    if ((p = realpath(name, buf)) == name && name != NULL)
        if (buf == NULL)
        {                                       /* NULL output buffer */
            errno = EFAULT;
            p = NULL;
        }
        else
        {                                       /* 'abs' match, copy to dest */
            (void) strcpy(buf, name);
            p = buf;
        }
    return (p);

#elif defined(WIN32)
    const char *p;

                                                /* restore full path */
    if ((p = _fullpath(buf, name, PATH_MAX)) == NULL && name != NULL)
        if (buf == NULL)
        {                                       /* NULL output buffer */
            errno = EFAULT;
            p = NULL;
        }
        else
        {                                       /* 'abs' match, copy to dest */
            (void) strcpy(buf, name);
            p = buf;
        }
    return (p);

#elif defined(MSDOS)
    char sep;

    sep = strchr(name, '/') ? '/' : '\\';       /* handle UNIX, default MSDOS */
    (void) dos_realpath(name, buf, sep);
    return (buf);

#else
#error Unknown target OS ...
#endif
}


#if defined(MSDOS)
/* realpath ---
 *
 *  Takes as input an arbitrary path.  Fixes up the path by:
 *      1.  Convert relative path to absolute
 *      2.  Removing consecutive slashes
 *      3.  Removing trailing slashes
 *      4.  Making the path absolute if it wasn't already
 *      5.  Removing "." in the path
 *      6.  Removing ".." entries in the path (and the directory above them)
 */
static char         *get_cwd(char *out, int drive, char sep);

static void
dos_realpath( const char *in, char *out, char sep )
{
    register const char *i = in;
    register char *o = out;

/* Convert relative path to absolute */
    {
        int drive;

        if (*(i+1) == ':' &&
                ((*i >= 'a' && *i <= 'z') || (*i >= 'A' && *i <= 'Z'))) {
            if (*i >= 'a' && *i <= 'z')
                drive = *i - 'a';
            else drive = *i - 'A';
            *o++ = *i++;
            *o++ = *i++;
        } else {
            drive = GetDisk();
            *o++ = drive + 'A';
            *o++ = ':';
        }
        if (!is_slash(*i))
            o = get_cwd(o, drive, sep);
    }

/* Step through the input path */
    while (*i != '\0')
    {
    /* Skip input slashes */
        if (is_slash(*i))
        {
            i++;
            continue;
        }

    /* Skip "." and output nothing */
        if (*i == '.' && is_term(*(i + 1)))
        {
            i++; continue;
        }

    /* Skip ".." and remove previous output directory */
        if (*i == '.' && *(i + 1) == '.' && is_term(*(i + 2)))
        {
        /* Don't back up over drive spec or consume ../.. */
            if (o > out+2 && strncmp(o-2, "..", 2) != 0)
            {
            /* Consume .. and parent directory */
                i += 2;
                while (--o > out+2 && !is_slash(*o))
                    ;
                continue;
            }
        }

    /* Copy path component from in to p */
        *o++ = sep;

    /* Copy next filename/directory */
        while (!is_term(*i))
            *o++ = *i++;
    }
    *o = '\0';
}


static int
get_disk(void)
{
#ifdef __WATCOMC__
    unsigned drive;
    _dos_getdrive(&drive);
    return 0;
#else
    union REGS regs;
    regs.h.ah = 0x19;                           /* DOS Get Default Drive call */
    regs.h.al = 0;
    (void) intdos(&regs, &regs);
    return regs.h.al;
#endif
}


static char *
get_cwd(char *out, int drive, char sep)
{
    char cwd[ PATH_MAX ];
    register char *p, *o;

/* Get current work directory */
    {
        union REGS  regs;
        regs.h.ah   = 0x47;
        regs.h.dl   = drive + 1;
    #ifdef __386__
        regs.x.esi  = (unsigned long) cwd;
    #else
        regs.x.si   = (unsigned long) cwd;
    #endif
        (void) intdos(&regs, &regs);
    #ifdef __WATCOMC__
        if (regs.w.cflag != 0) {
            errno = regs.w.ax;
            return out;
        }
    #else
        if (regs.x.cflag != 0) {
            errno = regs.x.ax;
            return out;
        }
    #endif
    }

/* Copy and convert path */
    for (p = cwd, o = out+1; *p; p++)
         *o++ = is_slash(*p) ? sep : *p;
    *o = '\0';

/* Root path, don't insert "/", it'll be added later */
    if (*(out+1) != '\0')
        *out = sep;
    else *out = '\0';
    return (out + strlen(out));
}
#endif  /*MSDOS*/