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.

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:

// 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;
}

Top White Papers and Webcasts

Live Event Date: March 19, 2015 @ 1:00 p.m. ET / 10:00 a.m. PT
The 2015 Enterprise Mobile Application Survey asked 250 mobility professionals what their biggest mobile challenges are, how many employees they are equipping with mobile apps, and their methods for driving value with mobility.
Join Dan Woods, Editor and CTO of CITO Research, and Alan Murray, SVP of Products at Apperian, as they break down the results of this survey and discuss how enterprises are using mobile application management and private …

On-demand Event
Event Date: February 12, 2015
The evolution of systems engineering with the SysML modeling language has resulted in improved requirements specification, better architectural definition, and better hand-off to downstream engineering. Agile methods have proven successful in the software domain, but how can these methods be applied to systems engineering? Check out this webcast and join Bruce Powel Douglass, author of Real-Time Agility, as he discusses how agile methods have had a tremendous …