Previous section   Next section

Practical Programming in Tcl & Tk, Third Edition
By Brent B. Welch

Table of Contents
Chapter 9.  Working with Files and Programs

Cross-Platform File Naming

Files are named differently on UNIX, Windows, and Macintosh. UNIX separates file name components with a forward slash (/), Macintosh separates components with a colon (:), and Windows separates components with a backslash (\). In addition, the way that absolute and relative names are distinguished is different. For example, these are absolute pathnames for the Tcl script library (i.e., $tcl_library) on Macintosh, Windows, and UNIX, respectively:

Disk:System Folder:Extensions:Tool Command Language:tcl7.6
c:\Program Files\Tcl\lib\Tcl7.6

The good news is that Tcl provides operations that let you deal with file pathnames in a platform-independent manner. The file operations described in this chapter allow either native format or the UNIX naming convention. The backslash used in Windows pathnames is especially awkward because the backslash is special to Tcl. Happily, you can use forward slashes instead:

c:/Program Files/Tcl/lib/Tcl7.6

There are some ambiguous cases that can be specified only with native pathnames. On my Macintosh, Tcl and Tk are installed in a directory that has a slash in it. You can name it only with the native Macintosh name:

Disk:Applications:Tcl/Tk 4.2

Another construct to watch out for is a leading // in a file name. This is the Windows syntax for network names that reference files on other computers. You can avoid accidentally constructing a network name by using the file join command described next. Of course, you can use network names to access remote files.

If you must communicate with external programs, you may need to construct a file name in the native syntax for the current platform. You can construct these names with file join described later. You can also convert a UNIX-like name to a native name with file nativename.

Several of the file operations operate on pathnames as opposed to returning information about the file itself. You can use the dirname, extension, join, pathtype, rootname, split, and tail operations on any string; there is no requirement that the pathnames refer to an existing file.

Building up Pathnames: file join

You can get into trouble if you try to construct file names by simply joining components with a slash. If part of the name is in native format, joining things with slashes will result in incorrect pathnames on Macintosh and Windows. The same problem arises when you accept user input. The user is likely to provide file names in native format. For example, this construct will not create a valid pathname on the Macintosh because $tcl_library is in native format:

set file $tcl_library/init.tcl


Use file join to construct file names.

The platform-independent way to construct file names is with file join. The following command returns the name of the init.tcl file in native format:

set file [file join $tcl_library init.tcl]

The file join operation can join any number of pathname components. In addition, it has the feature that an absolute pathname overrides any previous components. For example (on UNIX), /b/c is an absolute pathname, so it overrides any paths that come before it in the arguments to file join:

file join a b/c d
=> a/b/c/d
file join a /b/c d
=> /b/c/d

On Macintosh, a relative pathname starts with a colon, and an absolute pathname does not. To specify an absolute path, you put a trailing colon on the first component so that it is interpreted as a volume specifier. These relative components are joined into a relative pathname:

file join a :b:c d
=> :a:b:c:d

In the next case, b:c is an absolute pathname with b: as the volume specifier. The absolute name overrides the previous relative name:

file join a b:c d
=> b:c:d

The file join operation converts UNIX-style pathnames to native format. For example, on Macintosh you get this:

file join /usr/local/lib
=> usr:local:lib

Chopping Pathnames: split, dirname, tail

The file split command divides a pathname into components. It is the inverse of file join. The split operation detects automatically if the input is in native or UNIX format. The results of file split may contain some syntax to help resolve ambiguous cases when the results are passed back to file join. For example, on Macintosh a UNIX-style pathname is split on slash separators. The Macintosh syntax for a volume specifier (Disk:) is returned on the leading component:

file split "/Disk/System Folder/Extensions"
=> Disk: {System Folder} Extensions

A common reason to split up pathnames is to divide a pathname into the directory part and the file part. This task is handled directly by the dirname and tail operations. The dirname operation returns the parent directory of a pathname, while tail returns the trailing component of the pathname:

file dirname /a/b/c
=> /a/b
file tail /a/b/c
=> c

For a pathname with a single component, the dirname option returns ".", on UNIX and Windows, or ":" on Macintosh. This is the name of the current directory.

The extension and root options are also complementary. The extension option returns everything from the last period in the name to the end (i.e., the file suffix including the period.) The root option returns everything up to, but not including, the last period in the pathname:

file root /a/b.c
=> /a/b
file extension /a/b.c
=> .c

      Previous section   Next section