Function to Determine a File's Relative Path

As far as I can see, there is no API function to do what I want so I have written one.

What GetRelativeFilename does is to take a base directory and an absolute filename and return a relative filename. For example:

Base Directory: c:\foo\bar
Filename: c:\foo\bar\myfile.txt
Relative name: myfile.txt

Base Directory: c:\foo\bar
Filename: c:\foo\myfile.txt
Relative name: ..\myfile.txt

Base Directory: c:\foo\bar
Filename: c:\goo\gia\myfile.txt
Relative name: ..\..\goo\gai\myfile.txt

You can use the various #defines to customise the function. MAX_FILENAME_LEN speaks for itself, ABSOLUTE_NAME_START controls the characters which are ignored at the start of an absolute filename ("c:\" for dos = 3 characters, "\" for unix = 1 character). SLASH is the character that separates directory names, i.e. '\\' for dos.

The function prototype is:


char* GetRelativeFilename(char *currentDirectory, char *absoluteFilename);
Both currentDirectory and absoluteFilename should be an absolute name, i.e. start with "c:\" for dos names or "/" for unix names. currentDirectory can end with a slash or not, it makes no difference.

To cope with dos drive letters, if the first character of currentDirectory is not equal to the first character of absoluteFilename, then an exact copy of absoluteFilename is returned. This should not be a problem with unix filenames as all absolute names start with "/". For example:

Base Directory: c:\foo\bar
Filename: d:\goo\gai\myfile.txt
Relative name: d:\goo\gai\myfile.txt

Here is the source code:


// GetRelativeFilename(), by Rob Fisher.
// rfisher@iee.org
// http://come.to/robfisher

// includes
#include 

// defines
#define MAX_FILENAME_LEN 512

// The number of characters at the start of an absolute filename.  e.g. in DOS,
// absolute filenames start with "X:\" so this value should be 3, in UNIX they start
// with "\" so this value should be 1.
#define ABSOLUTE_NAME_START 3

// set this to '\\' for DOS or '/' for UNIX
#define SLASH '\\'


// Given the absolute current directory and an absolute file name, returns a relative file name.
// For example, if the current directory is C:\foo\bar and the filename C:\foo\whee\text.txt is given,
// GetRelativeFilename will return ..\whee\text.txt.

char* GetRelativeFilename(char *currentDirectory, char *absoluteFilename)
{
	// declarations - put here so this should work in a C compiler
	int afMarker = 0, rfMarker = 0;
	int cdLen = 0, afLen = 0;
	int i = 0;
	int levels = 0;
	static char relativeFilename[MAX_FILENAME_LEN+1];

	cdLen = strlen(currentDirectory);
	afLen = strlen(absoluteFilename);
	
	// make sure the names are not too long or too short
	if(cdLen > MAX_FILENAME_LEN || cdLen < ABSOLUTE_NAME_START+1 || 
		afLen > MAX_FILENAME_LEN || afLen < ABSOLUTE_NAME_START+1)
	{
		return NULL;
	}
	
	// Handle DOS names that are on different drives:
	if(currentDirectory[0] != absoluteFilename[0])
	{
		// not on the same drive, so only absolute filename will do
		strcpy(relativeFilename, absoluteFilename);
		return relativeFilename;
	}

	// they are on the same drive, find out how much of the current directory
	// is in the absolute filename
	i = ABSOLUTE_NAME_START;
	while(i < afLen && i < cdLen && currentDirectory[i] == absoluteFilename[i])
	{
		i++;
	}

	if(i == cdLen && (absoluteFilename[i] == SLASH || absoluteFilename[i-1] == SLASH))
	{
		// the whole current directory name is in the file name,
		// so we just trim off the current directory name to get the
		// current file name.
		if(absoluteFilename[i] == SLASH)
		{
			// a directory name might have a trailing slash but a relative
			// file name should not have a leading one...
			i++;
		}

		strcpy(relativeFilename, &absoluteFilename[i]);
		return relativeFilename;
	}


	// The file is not in a child directory of the current directory, so we
	// need to step back the appropriate number of parent directories by
	// using "..\"s.  First find out how many levels deeper we are than the
	// common directory
	afMarker = i;
	levels = 1;

	// count the number of directory levels we have to go up to get to the
	// common directory
	while(i < cdLen)
	{
		i++;
		if(currentDirectory[i] == SLASH)
		{
			// make sure it's not a trailing slash
			i++;
			if(currentDirectory[i] != '\0')
			{
				levels++;
			}
		}
	}

	// move the absolute filename marker back to the start of the directory name
	// that it has stopped in.
	while(afMarker > 0 && absoluteFilename[afMarker-1] != SLASH)
	{
		afMarker--;
	}

	// check that the result will not be too long
	if(levels * 3 + afLen - afMarker > MAX_FILENAME_LEN)
	{
		return NULL;
	}
	
	// add the appropriate number of "..\"s.
	rfMarker = 0;
	for(i = 0; i < levels; i++)
	{
		relativeFilename[rfMarker++] = '.';
		relativeFilename[rfMarker++] = '.';
		relativeFilename[rfMarker++] = SLASH;
	}

	// copy the rest of the filename into the result string
	strcpy(&relativeFilename[rfMarker], &absoluteFilename[afMarker]);

	return relativeFilename;
}


Comments

  • Existing API

    Posted by Legacy on 07/30/1999 12:00am

    Originally posted by: Philip Lee

    Try PathRelativePathTo which is part of the shell lightweight utility APIs

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Lenovo recommends Windows 8 Pro. "I dropped my laptop getting out of the taxi." This probably sounds familiar to most IT professionals. If your employees are traveling, you know their devices are in for a rough go. Whether it's a trip to the conference room or a convention out of town, any time equipment leaves a user's desk it is at risk of being put into harm's way. Stay connected at all times, whether at the office or on the go, with agile, durable, and flexible devices like the Lenovo® …

  • U.S. companies are desperately trying to recruit and hire skilled software engineers and developers, but there is simply not enough quality talent to go around. Tiempo Development is a nearshore software development company. Our headquarters are in AZ, but we are a pioneer and leader in outsourcing to Mexico, based on our three software development centers there. We have a proven process and we are experts at providing our customers with powerful solutions. We transform ideas into reality.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date