PCA_LOOKUP_FILE(3TECLA) Interactive Command-line Input Library Functions

NAME


pca_lookup_file, del_PathCache, del_PcaPathConf, new_PathCache,
new_PcaPathConf, pca_last_error, pca_path_completions, pca_scan_path,
pca_set_check_fn, ppc_file_start, ppc_literal_escapes - lookup a file in
a list of directories

SYNOPSIS


cc [ flag... ] file... -ltecla [ library... ]
#include <libtecla.h>

char *pca_lookup_file(PathCache *pc, const char *name,
int name_len, int literal);


PathCache *del_PathCache(PathCache *pc);


PcaPathConf *del_PcaPathConf(PcaPathConf *ppc);


PathCache *new_PathCache(void);


PcaPathConf *new_PcaPathConf(PathCache *pc);


const char *pca_last_error(PathCache *pc);


CPL_MATCH_FN(pca_path_completions);


int pca_scan_path(PathCache *pc, const char *path);


void pca_set_check_fn(PathCache *pc, CplCheckFn *check_fn,
void *data);


void ppc_file_start(PcaPathConf *ppc, int start_index);


void ppc_literal_escapes(PcaPathConf *ppc, int literal);


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.

#include <stdio.h>
#include <stdlib.h>
#include <libtecla.h>

int main(int argc, char *argv[])
{
int i;
/*
* Create a cache for executable files.
*/
PathCache *pc = new_PathCache();
if(!pc)
exit(1);
/*
* Scan the user's PATH for executables.
*/
if(pca_scan_path(pc, getenv("PATH"))) {
fprintf(stderr, "%s\n", pca_last_error(pc));
exit(1);
}
/*
* Arrange to only report executable files.
*/
pca_set_check_fn(pc, cpl_check_exe, NULL);
/*
* Lookup and display the full pathname of each of the
* commands listed on the command line.
*/
for(i=1; i<argc; i++) {
char *cmd = pca_lookup_file(pc, argv[i], -1, 0);
printf("The full pathname of '%s' is %s\\n", argv[i],
cmd ? cmd : "unknown");
}
pc = del_PathCache(pc); /* Clean up */
return 0;
}


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.

#define CPL_CHECK_FN(fn) int (fn)(void *data, const char *pathname)
typedef CPL_CHECK_FN(CplCheckFn);


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
dispositions 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.

ATTRIBUTES


See attributes(7) for descriptions of the following attributes:


+--------------------+-----------------+
| ATTRIBUTE TYPE | ATTRIBUTE VALUE |
+--------------------+-----------------+
|Interface Stability | Evolving |
+--------------------+-----------------+
|MT-Level | MT-Safe |
+--------------------+-----------------+

SEE ALSO


libtecla(3LIB), cpl_complete_word(3TECLA), ef_expand_file(3TECLA),
gl_get_line(3TECLA), attributes(7)

January 18, 2020 PCA_LOOKUP_FILE(3TECLA)