|
|
|
fnm_util
- Filename Utilities
The FNM_UTIL package provides a filename parsing capability inspired by the
VAX/VMS lexical function, f$parse()
. File specifications have
the following structure:
node:/directory(s)/name.extension.version
Any field is optional. node is a host name; directory is one
or more names separated by "/"s; name follows the last "/" in the
pathname. version is a 3-digit number (e.g., 002
) and
extension follows the last dot before the version dot.
A filename is created as follows:
#include "fnm_util.h" -- Filename utilities. FileName fname ; ... fname = fnmCreate ("fileSpec", NULL) ;
fnmCreate()
expands the file specification, translating
environment variable references and filling in defaults for missing fields.
fnmCreate()
can be passed multiple file specifications, which
are then processed from left to right in the calling sequence:
fname = fnmCreate ("spec1", ..., "specN", NULL) ;
First, the leftmost file specification is examined and any references to environment variables are translated. The next file specification is then examined. Environment variables are translated and fields missing in the first file specification are supplied from the new file specification. Subsequent file specifications are examined, in turn, and "applied" to the results of the processing of the previous file specifications. Finally, system defaults (e.g., the user's home directory) are supplied for missing fields that remain.
Is that clear? I used to have a diagram that showed the file names stacked up, one on top of another:
... System Defaults ... File_Spec_#N | ... | File_Spec_#2 | File_Spec_#1 V -------------- Result
File name components would drop down through holes in lower-level specifications to fill in missing fields in the result.
Specifying multiple file specifications is useful for replacing extensions, concatenating directories, etc.:
#include "fnm_util.h" -- Filename utilities. FileName fname ; ... -- "/usr/me" (current directory) fname = fnmCreate (NULL) ; -- "/usr/me/prog.lis" fname = fnmCreate (".lis", "prog.c", NULL) ; -- "/usr/you/tools/dump.o" fname = fnmCreate (".o", "tools/dump.c", "/usr/you/", NULL) ;
What can you do with a file name once it is created? You call
fnmParse()
to get the whole file name or parts of the file
name as a string:
#include "fnm_util.h" -- Filename utilities. char *s ; FileName fname ; ... fname = fnmCreate ("host:/usr/who/myprog.c.001", NULL) ; s = fnmParse (fname, FnmPath) ; -- "host:/usr/who/myprog.c.001" s = fnmParse (fname, FnmNode) ; -- "host:" s = fnmParse (fname, FnmDirectory) ; -- "/usr/who" s = fnmParse (fname, FnmFile) ; -- "myprog.c.001" s = fnmParse (fname, FnmName) ; -- "myprog" s = fnmParse (fname, FnmExtension) ; -- ".c" s = fnmParse (fname, FnmVersion) ; -- ".001" fnmDestroy (fname) ;
Shorthand macros - fnmPath()
, fnmNode()
, etc. -
are defined for each of the fnmParse()
calls above.
The FNM_UTIL package is a repackaging of my FPARSE package, which was
inspired by the VAX/VMS lexical function, f$parse()
.
fnmCreate()
- creates a filename.
fnmDestroy()
- destroys a filename.
fnmEnv()
- translates environment variable references in a
pathname; a wrapper around
strEnv()
fnmExists()
- checks if a file exists.
fnmGetCWD()
- gets the current working directory; a wrapper
around getcwd(3).
fnmParse()
- parses a filename.
fnmPath()
- returns a filename's full pathname.
fnmNode()
- returns the node from a filename.
fnmDirectory()
- returns the directory from a filename.
fnmFile()
- returns the file, extension, and version from a filename.
fnmName()
- returns the file from a filename.
fnmExtension()
- returns the extension from a filename.
fnmVersion()
- returns the version number from a filename.
fnm_util.c
fnm_util.h
(See libgpl
for the
complete source, including support routines and build files.)