Description

The PathCache object is part of the libtecla(3LIB) library. PathCache objects allow
an application to search for files in any colon separated list of directories,
such as the UNIX execution PATH environment variable. Files in absolute directories
are cached in a PathCache object, whereas relative directories are scanned as
needed. Using a PathCache object, you can look up the full pathname of
a simple filename, or you can obtain a list of the possible
completions of a given filename prefix. By default all files in the
list of directories are targets for lookup and completion, but a versatile
mechanism is provided for only selecting specific types of files. The obvious application
of this facility is to provide Tab-completion and lookup of executable commands
in the UNIX PATH, so an optional callback which rejects all but
executable files, is provided.

An Example

Under UNIX, the following example program looks up and displays the full
pathnames of each of the command names on the command line.

The following is an example of what this does on a laptop
under LINUX:

$ ./example less more blob
The full pathname of 'less' is /usr/bin/less
The full pathname of 'more' is /bin/more
The full pathname of 'blob' is unknown
$

Function Descriptions

To use the facilities of this module, you must first allocate a
PathCache object by calling the new_PathCache() constructor function. This function creates the
resources needed to cache and lookup files in a list of directories.
It returns NULL on error.

Populating The Cache

Once you have created a cache, it needs to be populated with
files. To do this, call the pca_scan_path() function. Whenever this function is
called, it discards the current contents of the cache, then scans the
list of directories specified in its path argument for files. The path argument
must be a string containing a colon-separated list of directories, such as
“/usr/bin:/home/mcs/bin:”. This can include directories specified by absolute pathnames such as “/usr/bin”,
as well as sub-directories specified by relative pathnames such as “.” or “bin”.
Files in the absolute directories are immediately cached in the specified PathCache
object, whereas subdirectories, whose identities obviously change whenever the current working directory is
changed, are marked to be scanned on the fly whenever a file
is looked up.

On success this function return 0. On error it returns 1, and
a description of the error can be obtained by calling pca_last_error(pc).

Looking Up Files

Once the cache has been populated with files, you can look up
the full pathname of a file, simply by specifying its filename to
pca_lookup_file().

To make it possible to pass this function a filename which is
actually part of a longer string, the name_len argument can be used
to specify the length of the filename at the start of the
name[] argument. If you pass -1 for this length, the length of the
string will be determined with strlen. If the name[] string might contain
backslashes that escape the special meanings of spaces and tabs within the
filename, give the literal argument the value 0. Otherwise, if backslashes should be
treated as normal characters, pass 1 for the value of the literal
argument.

Filename Completion

Looking up the potential completions of a filename-prefix in the filename cache
is achieved by passing the provided pca_path_completions() callback function to the cpl_complete_word(3TECLA)
function.

This callback requires that its data argument be a pointer to a
PcaPathConf object. Configuration objects of this type are allocated by calling new_PcaPathConf().

This function returns an object initialized with default configuration parameters, which determine
how the cpl_path_completions() callback function behaves. The functions which allow you to
individually change these parameters are discussed below.

By default, the pca_path_completions() callback function searches backwards for the start of
the filename being completed, looking for the first un-escaped space or the
start of the input line. If you wish to specify a different
location, call ppc_file_start() with the index at which the filename starts in the
input line. Passing start_index=-1 re-enables the default behavior.

By default, when pca_path_completions() looks at a filename in the input line,
each lone backslash in the input line is interpreted as being a
special character which removes any special significance of the character which follows
it, such as a space which should be taken as part of the
filename rather than delimiting the start of the filename. These backslashes are
thus ignored while looking for completions, and subsequently added before spaces, tabs
and literal backslashes in the list of completions. To have unescaped backslashes
treated as normal characters, call ppc_literal_escapes() with a non-zero value in its literal
argument.

When you have finished with a PcaPathConf variable, you can pass it
to the del_PcaPathConf() destructor function to reclaim its memory.

Being Selective

If you are only interested in certain types or files, such as,
for example, executable files, or files whose names end in a particular
suffix, you can arrange for the file completion and lookup functions to
be selective in the filenames that they return. This is done by
registering a callback function with your PathCache object. Thereafter, whenever a filename is
found which either matches a filename being looked up or matches a
prefix which is being completed, your callback function will be called with
the full pathname of the file, plus any application-specific data that you provide.
If the callback returns 1 the filename will be reported as a
match. If it returns 0, it will be ignored. Suitable callback functions
and their prototypes should be declared with the following macro. The CplCheckFn
typedef is also provided in case you wish to declare pointers to such
functions

Registering one of these functions involves calling the pca_set_check_fn() function. In addition
to the callback function passed with the check_fn argument, you can pass
a pointer to anything with the data argument. This pointer will be passed
on to your callback function by its own data argument whenever it
is called, providing a way to pass application-specific data to your callback.
Note that these callbacks are passed the full pathname of each matching
file, so the decision about whether a file is of interest can be
based on any property of the file, not just its filename. As
an example, the provided cpl_check_exe() callback function looks at the executable permissions
of the file and the permissions of its parent directories, and only
returns 1 if the user has execute permission to the file. This callback
function can thus be used to lookup or complete command names found
in the directories listed in the user's PATH environment variable. The example
program above provides a demonstration of this.

Beware that if somebody tries to complete an empty string, your callback
will get called once for every file in the cache, which could
number in the thousands. If your callback does anything time consuming, this
could result in an unacceptable delay for the user, so callbacks should
be kept short.

To improve performance, whenever one of these callbacks is called, the choice
that it makes is cached, and the next time the corresponding file
is looked up, instead of calling the callback again, the cached record
of whether it was accepted or rejected is used. Thus if somebody
tries to complete an empty string, and hits tab a second time when
nothing appears to happen, there will only be one long delay, since
the second pass will operate entirely from the cached dispositions of the
files. These cached dipositions are discarded whenever pca_scan_path() is called, and whenever pca_set_check_fn()
is called with changed callback function or data arguments.

Error Handling

If pca_scan_path() reports that an error occurred by returning 1, you can
obtain a terse description of the error by calling pca_last_error(pc). This returns
an internal string containing an error message.

Cleaning Up

Once you have finished using a PathCache object, you can reclaim its
resources by passing it to the del_PathCache() destructor function. This takes a
pointer to one of these objects, and always returns NULL.

Thread Safety

It is safe to use the facilities of this module in multiple
threads, provided that each thread uses a separately allocated PathCache object. In
other words, if two threads want to do path searching, they should
each call new_PathCache() to allocate their own caches.