Converting an absolute path to a relative path
This lesson demonstrates how to convert an absolute file path to a relative file path.
The relativePath function takes two parameters
pFilePath: the absolute file path, that is, a file path that starts at the top of the folder structure and names each enclosing folder on the way to the file
pFolder: an optional folder where the relative path should start, if this parameter is not specified the current folder is used.
The function is called with a statement such as:
put relativePath(it,myFolder) into pathToUse
set the fileLoc of me to relativePath(thisPath)
The relativePath function works by comparing the absolute path and the starting folder side by side, and removing the parts of the structure that are common to both paths. Then it figures out how many levels up the relative path needs to move to get to the starting folder, and prepends the appropriate number of "../" to the start of the relative path. Finally, it returns the new path.
The first thing the function does is make sure pFilePath is, in fact, an absolute path. The rule for determining whether a path is an absolute path is as follows:
* On Windows systems, absolute paths begin with a drive letter followed by a colon character.
* On all other operating systems, absolute paths begin with a slash.
To figure out whether pFilePath meets these conditions, the function uses a complex expression with the and and or operators. If the function is running on Windows, and either the first character isn't a letter or the second character isn't a colon, this isn't an absolute path. If the function is running on another platform and the first character isn't a slash, this isn't an absolute path. These two conditions are each enclosed in parentheses and are joined by the or operator, so if either of them is true, the condition itself is true and LiveCode executes the contents of the if statement.
if (the platform is "Win32" and (char 1 of pFilePath is not in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ or char 2 of pFilePath is not ":")) \ or (the platform is not "Win32" and \ char 1 of pFilePath is not "/") then return "Error: path is not an absolute path" end if
If pFilePath is not actually an absolute path, the handler uses the return control structure to pass an error message back to the calling handler.
Next, the handler checks pFolder. If nothing was passed in pFolder, the handler uses the current folder as the default for this parameter. You can use this method with any handler to assign a default value to one or more of the parameters. Just check whether the parameter is empty. If it is, then no value has been passed, and you can simply put the desired default into the parameter.
if pFolder is empty then put the defaultFolder into pFolder end if
The relative path to the current folder is ".", so if pFilePath and pFolder are the same, the function returns ".".
if pFilePath is pFolder then return "." end if
Now the handler begins comparing the two absolute paths, pFilePath and pFolder, to see what parts of the folder structure they have in common. Let's look at two paths to see how this comparison works.
Suppose pFolder is "/Disk/Applications/Spreadsheets/" and pFilePath is "/Disk/Applications/Graphics/ImageEdit". The first two parts, the first two items, with the itemDelimiter set to "/", are the same, so they won't be needed to create a relative path that starts from one and moves to the other.
set the itemDelimiter to "/" repeat if item 1 of pFolder is item 1 of pFilePath then ## they're in the same disk or folder delete item 1 of pFilePath delete item 1 of pFolder else exit repeat end if end repeat
The repeat control structure moves through the two paths, item by item, and deletes the items they have in common. When the loop comes to an item that they don't have in common, it uses the exit repeat control structure to stop the loop. (Because we're using the simple repeat form of the repeat control structure--which can also be written repeat forever--we need to execute an exit repeat at some point. Otherwise, the repeat loop would just keep going.)
The pFolder variable now is "Spreadsheets/", and pFilePath is "Graphics/ImageEdit". This is the part of pFilePath that isn't in common with pFolder, so it's the part that's essential to finding the "ImageEdit" file from pFolder.
We need to do one more thing: figure out how many levels from pFolder to move up before we can find the "Graphics" folder. We can find this out by looking at what's left of pFolder. The number of items remaining in pFolder is the number of levels we will have to move up. The string "../" in a relative path means "go up one level", so we prepend this string the necessary number of times to pFilePath.
repeat for (the number of items in pFolder) times put "../" before pFilePath end repeat return pFilePath
In our example, there's one item left in pFolder, so the final relative path is "../Graphics/ImageEdit". This means "Starting at the Spreadsheets folder, go up one level to Applications. Then go down to the Graphics folder, and down once more to the ImageEdit file." You can read the relative path as a list of directions for how to start from the original pFolder and get to the destination.
function relativePath pFilePath, pFolder if (the platform is "Win32" and (char 1 of pFilePath is not in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ or char 2 of pFilePath is not ":")) \ or (the platform is not "Win32" and \ char 1 of pFilePath is not "/") then return "Error: path is not an absolute path" end if if pFolder is empty then put the defaultFolder into pFolder end if if pFilePath is pFolder then return "." end if set the itemDelimiter to "/" repeat if item 1 of pFolder is item 1 of pFilePath then ## they're in the same disk or folder delete item 1 of pFilePath delete item 1 of pFolder else exit repeat end if end repeat repeat for (the number of items in pFolder) times put "../" before pFilePath end repeat return pFilePath end relativePath