Category : C++ Source Code
Archive   : VCCRT1.ZIP
Filename : FULLPATH.C

 
Output of file : FULLPATH.C contained in archive : VCCRT1.ZIP
/***
*fullpath.c - Create a full pathname from components
*
* Copyright (c) 1987-1992, Microsoft Corporation. All rights reserved.
*
*Purpose: contains the function _fullpath which makes an absolute path out
* of a relative path. i.e. ..\pop\..\main.c => c:\src\main.c if the
* current directory is c:\src\src
*
*Revision History:
*
* 12-21-87 WAJ Initial version
* 01-08-88 WAJ now treats / as an \
* 06-22-88 WAJ now handles network paths ie \\sl\users
* 01-31-89 SKS/JCR Renamed _canonic to _fullpath
* 04-03-89 WAJ Now returns "d:\dir" for "."
* 05-09-89 SKS Do not change the case of arguments
* 11-27-89 GJF Fixed copyright
* 11-30-89 JCR Preserve errno setting from _getdcwd() call on errors
* 04-11-90 JCR ANSI naming, etc.
* 04-25-90 JCR Fixed an incorrect errno setting
* 06-14-90 SBM Fixed bugs in which case of user provided drive letter
* was not always preserved, and c:\foo\\bar did not
* generate an error
* 06-19-90 SBM Compiles cleanly with -W3
* 08-28-90 SBM Fixed bug in which UNC names were being rejected
* 08-05-91 JLM Addes MBCS support under switches.
* 02-14-92 JCR MBCS bug fix
*
*******************************************************************************/

#include
#include
#include
#include
#include

#ifdef _MBCS
#include
#include
int isdbcscode (char *, char*);
#endif

#define ISSLASH(a) ((a) == '\\' || (a) == '/')

/***
*char *_fullpath( char *buf, const char *path, maxlen );
*
*Purpose:
*
* _fullpath - combines the current directory with path to form
* an absolute path. i.e. _fullpath takes care of .\ and ..\
* in the path.
*
* The result is placed in buf. If the length of the result
* is greater than maxlen NULL is returned, otherwise
* the address of buf is returned.
*
* If buf is NULL then a buffer is malloc'ed and maxlen is
* ignored. If there are no errors then the address of this
* buffer is returned.
*
* If path specifies a drive, the curent directory of this
* drive is combined with path. If the drive is not valid
* and _fullpath needs the current directory of this drive
* then NULL is returned. If the current directory of this
* non existant drive is not needed then a proper value is
* returned.
* For example: path = "z:\\pop" does not need z:'s current
* directory but path = "z:pop" does.
*
*
*
*Entry:
* char *buf - pointer to a buffer maintained by the user;
* char *path - path to "add" to the current directory
* int maxlen - length of the buffer pointed to by buf
*
*Exit:
* Returns pointer to the buffer containing the absolute path
* (same as buf if non-NULL; otherwise, malloc is
* used to allocate a buffer)
*
*Exceptions:
*
*******************************************************************************/


char * _fullpath( char *UserBuf, const char *path, size_t maxlen )
{
char *RetValue;
char *buf;
char *StartBuf;
char *EndBuf;
char c;
int count;
unsigned drive;


if( !path || !*path ) /* no work to do */
return( _getcwd( UserBuf, maxlen ) );

/* allocate buffer if necessary */

if( !UserBuf )
if( !(buf = malloc(_MAX_PATH)) ){
errno = ENOMEM;
return( NULL );
}
else
maxlen = _MAX_PATH;

else {
if( maxlen < _MAX_DRIVE+1 ){ /* we need at least 4 chars for "A:\" */
errno = ERANGE;
return( NULL );
}
buf = UserBuf;
}

RetValue = buf;
EndBuf = buf + maxlen - 1;

if( ISSLASH(*(path+1)) && ISSLASH(*path) ){ /* check for network drive */

count = 0; /* count the '\\'s */
while( (c = *path) ){
*buf = c;
path++;

if( buf >= EndBuf ){
ReturnError1:
errno = ERANGE;
ReturnError2:
if( UserBuf == NULL )
free( RetValue );
return( NULL );
}

#ifdef _MBCS
if ( !_ISLEADBYTE(*(buf-2)))
#endif
if( ISSLASH( c ) ){
/* ensure that path contains a '\\', not a '/' */
*buf = '\\';

/* ensure that '\\\\' is followed by something */
if( ++count == 2 ){
if( !*path ){
errno = EINVAL;
goto ReturnError2;
}
}

/* check that third and fourth '\\'are preceded by non-'\\' */
if( count >= 3 ){
if( *(buf-1) == '\\' ){
errno = EINVAL;
goto ReturnError2;
}
}

/* stop on fourth '\\', \\foo\bar\ <-- namely this one */
if( count == 4 )
break;
}

buf++;
}

*buf = '\\';
StartBuf = buf;
}

else { /* not a UNC path */

if( path[1] == ':' ){ /* get drive information */
*buf = *path;
/*
** drive must be in the range 1-26
** "*buf" may be upper or lower case
*/
drive = (*buf++ - 'A' + 1) & 0x1F;
*buf++ = ':';
path += 2;
}
else
drive = 0;

if( ISSLASH( *path ) ){
if( drive == 0 ){
*buf++ = (char)(_getdrive() + 'A' - 1);
*buf++ = ':';
}

path++;
}

else {
/* preserve the driveletter in original case from path,
since _getdcwd will always return it in upper case */
if (drive)
c = *(path-2);
if( !_getdcwd( drive, RetValue, maxlen ) )
goto ReturnError2; /* error: preserve errno value */
buf = RetValue + strlen( RetValue );
/* restore drive letter in original case */
if (drive)
*RetValue = c;
#ifdef _MBCS
if (!_ISLEADBYTE(*(buf-2)))
#endif
if( ISSLASH( *(buf-1) ) ) /* buf must point to last slash */
buf--; /* if this is a root directory */
}

*buf = '\\';
StartBuf = RetValue + 2;
}


while( *path ){

if( *path == '.'
&& *(path+1) == '.'
&& ( ISSLASH(*(path+2)) || !*(path+2) ) ){ /* handle .. */

do{
buf--;
#ifdef _MBCS
if (ISSLASH(*buf))
if (isdbcscode(StartBuf,buf))
buf--;
#endif
}
while( !ISSLASH( *buf ) && buf > StartBuf );

if( buf < StartBuf ) { /* unable to do cd .. */
errno = EACCES;
goto ReturnError2;
}

path += 2;
if( *path ) /* if it was "..\" */
path++;
}

else if( *path == '.' && ( ISSLASH(*(path+1)) || !*(path+1) )){

path++; /* handle . */
if( *path ) /* if it was ".\" */
path++;
}

else {
while( !ISSLASH( *path ) && *path && buf < EndBuf ){
*++buf = *path++;
#ifdef _MBCS
if (_ISLEADBYTE(*(path-1)))
*++buf = *path++;
#endif
}

if( buf >= EndBuf ) /* if buf == EndBuf then */
goto ReturnError1; /* no room for '\0' */

/* test for non-empty path component */
if( *buf == '\\' ){
errno = EINVAL;
goto ReturnError2;
}

*++buf = '\\';
if( ISSLASH( *path ) )
path++;
}
}


/* buf points to last character in the string which is an '\\' */

if( *(buf-1) == ':' ) /* keep trailing '\' if */
buf++; /* this is a root directory */
*buf = '\0';

return( RetValue );
}


#ifdef _MBCS
/***
* int isdbcscode( char *path, char *buf );
*
*Purpose:
*
* isdbcscode - Check DBCS Code
*
*Entry:
* char *path - full path
* char *buf - pointer to a buffer maintained by the user;
*
*Exit:
* TRUE : -1
* FALSE : 0
*
*Exceptions:
*
*******************************************************************************/

int isdbcscode(char *path, char *buf)
{
while(path <= buf && *path++) {
if(_ISLEADBYTE( *(path - 1) ) )
if(path == buf)
return(-1);
else
path++;
}

return(0);

}
#endif


  3 Responses to “Category : C++ Source Code
Archive   : VCCRT1.ZIP
Filename : FULLPATH.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/