summaryrefslogtreecommitdiff
path: root/libtecla-1.4.1/cplfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'libtecla-1.4.1/cplfile.c')
-rw-r--r--libtecla-1.4.1/cplfile.c874
1 files changed, 0 insertions, 874 deletions
diff --git a/libtecla-1.4.1/cplfile.c b/libtecla-1.4.1/cplfile.c
deleted file mode 100644
index 73eef1d..0000000
--- a/libtecla-1.4.1/cplfile.c
+++ /dev/null
@@ -1,874 +0,0 @@
-/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
- *
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, and/or sell copies of the Software, and to permit persons
- * to whom the Software is furnished to do so, provided that the above
- * copyright notice(s) and this permission notice appear in all copies of
- * the Software and that both the above copyright notice(s) and this
- * permission notice appear in supporting documentation.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
- * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
- * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Except as contained in this notice, the name of a copyright holder
- * shall not be used in advertising or otherwise to promote the sale, use
- * or other dealings in this Software without prior written authorization
- * of the copyright holder.
- */
-
-/*
- * Standard includes.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
-
-/*
- * Local includes.
- */
-#include "libtecla.h"
-#include "direader.h"
-#include "homedir.h"
-#include "pathutil.h"
-#include "cplfile.h"
-
-/*
- * Set the maximum length allowed for usernames.
- * names.
- */
-#define USR_LEN 100
-
-/*
- * Set the maximum length allowed for environment variable names.
- */
-#define ENV_LEN 100
-
-/*
- * Set the max length of the error-reporting string. There is no point
- * in this being longer than the width of a typical terminal window.
- * In composing error messages, I have assumed that this number is
- * at least 80, so you don't decrease it below this number.
- */
-#define ERRLEN 200
-
-/*
- * The resources needed to complete a filename are maintained in objects
- * of the following type.
- */
-struct CompleteFile {
- DirReader *dr; /* A directory reader */
- HomeDir *home; /* A home directory expander */
- PathName *path; /* The buffer in which to accumulate the path */
- PathName *buff; /* A pathname work buffer */
- char usrnam[USR_LEN+1]; /* The buffer used when reading the names of */
- /* users. */
- char envnam[ENV_LEN+1]; /* The buffer used when reading the names of */
- /* environment variables. */
- char errmsg[ERRLEN+1]; /* The error-report buffer */
-};
-
-static int cf_expand_home_dir(CompleteFile *cf, const char *user);
-static int cf_complete_username(CompleteFile *cf, WordCompletion *cpl,
- const char *prefix, const char *line,
- int word_start, int word_end, int escaped);
-static HOME_DIR_FN(cf_homedir_callback);
-static int cf_complete_entry(CompleteFile *cf, WordCompletion *cpl,
- const char *line, int word_start, int word_end,
- int escaped, CplCheckFn *check_fn,
- void *check_data);
-static char *cf_read_name(CompleteFile *cf, const char *type,
- const char *string, int slen,
- char *nambuf, int nammax);
-static int cf_prepare_suffix(CompleteFile *cf, const char *suffix,
- int add_escapes);
-
-/*
- * A stack based object of the following type is used to pass data to the
- * cf_homedir_callback() function.
- */
-typedef struct {
- CompleteFile *cf; /* The file-completion resource object */
- WordCompletion *cpl; /* The string-completion rsource object */
- const char *prefix; /* The username prefix to be completed */
- const char *line; /* The line from which the prefix was extracted */
- int word_start; /* The index in line[] of the start of the username */
- int word_end; /* The index in line[] following the end of the prefix */
- int escaped; /* If true, add escapes to the completion suffixes */
-} CfHomeArgs;
-
-/*.......................................................................
- * Create a new file-completion object.
- *
- * Output:
- * return CompleteFile * The new object, or NULL on error.
- */
-CompleteFile *_new_CompleteFile(void)
-{
- CompleteFile *cf; /* The object to be returned */
-/*
- * Allocate the container.
- */
- cf = (CompleteFile *) malloc(sizeof(CompleteFile));
- if(!cf) {
- fprintf(stderr, "_new_CompleteFile: Insufficient memory.\n");
- return NULL;
- };
-/*
- * Before attempting any operation that might fail, initialize the
- * container at least up to the point at which it can safely be passed
- * to _del_CompleteFile().
- */
- cf->dr = NULL;
- cf->home = NULL;
- cf->path = NULL;
- cf->buff = NULL;
- cf->usrnam[0] = '\0';
- cf->envnam[0] = '\0';
- cf->errmsg[0] = '\0';
-/*
- * Create the object that is used for reading directories.
- */
- cf->dr = _new_DirReader();
- if(!cf->dr)
- return _del_CompleteFile(cf);
-/*
- * Create the object that is used to lookup home directories.
- */
- cf->home = _new_HomeDir();
- if(!cf->home)
- return _del_CompleteFile(cf);
-/*
- * Create the buffer in which the completed pathname is accumulated.
- */
- cf->path = _new_PathName();
- if(!cf->path)
- return _del_CompleteFile(cf);
-/*
- * Create a pathname work buffer.
- */
- cf->buff = _new_PathName();
- if(!cf->buff)
- return _del_CompleteFile(cf);
- return cf;
-}
-
-/*.......................................................................
- * Delete a file-completion object.
- *
- * Input:
- * cf CompleteFile * The object to be deleted.
- * Output:
- * return CompleteFile * The deleted object (always NULL).
- */
-CompleteFile *_del_CompleteFile(CompleteFile *cf)
-{
- if(cf) {
- cf->dr = _del_DirReader(cf->dr);
- cf->home = _del_HomeDir(cf->home);
- cf->path = _del_PathName(cf->path);
- cf->buff = _del_PathName(cf->buff);
- free(cf);
- };
- return NULL;
-}
-
-/*.......................................................................
- * Look up the possible completions of the incomplete filename that
- * lies between specified indexes of a given command-line string.
- *
- * Input:
- * cpl WordCompletion * The object in which to record the completions.
- * cf CompleteFile * The filename-completion resource object.
- * line const char * The string containing the incomplete filename.
- * word_start int The index of the first character in line[]
- * of the incomplete filename.
- * word_end int The index of the character in line[] that
- * follows the last character of the incomplete
- * filename.
- * escaped int If true, backslashes in line[] are
- * interpreted as escaping the characters
- * that follow them, and any spaces, tabs,
- * backslashes, or wildcard characters in the
- * returned suffixes will be similarly escaped.
- * If false, backslashes will be interpreted as
- * literal parts of the file name, and no
- * backslashes will be added to the returned
- * suffixes.
- * check_fn CplCheckFn * If not zero, this argument specifies a
- * function to call to ask whether a given
- * file should be included in the list
- * of completions.
- * check_data void * Anonymous data to be passed to check_fn().
- * Output:
- * return int 0 - OK.
- * 1 - Error. A description of the error can be
- * acquired by calling _cf_last_error(cf).
- */
-int _cf_complete_file(WordCompletion *cpl, CompleteFile *cf,
- const char *line, int word_start, int word_end,
- int escaped, CplCheckFn *check_fn, void *check_data)
-{
- const char *lptr; /* A pointer into line[] */
- int nleft; /* The number of characters still to be processed */
- /* in line[]. */
-/*
- * Check the arguments.
- */
- if(!cpl || !cf || !line || word_end < word_start) {
- if(cf)
- strcpy(cf->errmsg, "_cf_complete_file: Invalid arguments");
- return 1;
- };
-/*
- * Clear the buffer in which the filename will be constructed.
- */
- _pn_clear_path(cf->path);
-/*
- * How many characters are to be processed?
- */
- nleft = word_end - word_start;
-/*
- * Get a pointer to the start of the incomplete filename.
- */
- lptr = line + word_start;
-/*
- * If the first character is a tilde, then perform home-directory
- * interpolation.
- */
- if(nleft > 0 && *lptr == '~') {
- int slen;
- if(!cf_read_name(cf, "User", ++lptr, --nleft, cf->usrnam, USR_LEN))
- return 1;
-/*
- * Advance over the username in the input line.
- */
- slen = strlen(cf->usrnam);
- lptr += slen;
- nleft -= slen;
-/*
- * If we haven't hit the end of the input string then we have a complete
- * username to translate to the corresponding home directory.
- */
- if(nleft > 0) {
- if(cf_expand_home_dir(cf, cf->usrnam))
- return 1;
-/*
- * ~user and ~ are usually followed by a directory separator to
- * separate them from the file contained in the home directory.
- * If the home directory is the root directory, then we don't want
- * to follow the home directory by a directory separator, so we should
- * skip over it so that it doesn't get copied into the filename.
- */
- if(strcmp(cf->path->name, FS_ROOT_DIR) == 0 &&
- strncmp(lptr, FS_DIR_SEP, FS_DIR_SEP_LEN) == 0) {
- lptr += FS_DIR_SEP_LEN;
- nleft -= FS_DIR_SEP_LEN;
- };
-/*
- * If we have reached the end of the input string, then the username
- * may be incomplete, and we should attempt to complete it.
- */
- } else {
-/*
- * Look up the possible completions of the username.
- */
- return cf_complete_username(cf, cpl, cf->usrnam, line, word_start+1,
- word_end, escaped);
- };
- };
-/*
- * Copy the rest of the path, stopping to expand $envvar expressions
- * where encountered.
- */
- while(nleft > 0) {
- int seglen; /* The length of the next segment to be copied */
-/*
- * Find the length of the next segment to be copied, stopping if an
- * unescaped '$' is seen, or the end of the path is reached.
- */
- for(seglen=0; seglen < nleft; seglen++) {
- int c = lptr[seglen];
- if(escaped && c == '\\')
- seglen++;
- else if(c == '$')
- break;
-/*
- * We will be completing the last component of the file name,
- * so whenever a directory separator is seen, assume that it
- * might be the start of the last component, and mark the character
- * that follows it as the start of the name that is to be completed.
- */
- if(nleft >= FS_DIR_SEP_LEN &&
- strncmp(lptr + seglen, FS_DIR_SEP, FS_DIR_SEP_LEN)==0) {
- word_start = (lptr + seglen) - line + FS_DIR_SEP_LEN;
- };
- };
-/*
- * We have reached either the end of the filename or the start of
- * $environment_variable expression. Record the newly checked
- * segment of the filename in the output filename, removing
- * backslash-escapes where needed.
- */
- if(_pn_append_to_path(cf->path, lptr, seglen, escaped) == NULL) {
- strcpy(cf->errmsg, "Insufficient memory to complete filename");
- return 1;
- };
- lptr += seglen;
- nleft -= seglen;
-/*
- * If the above loop finished before we hit the end of the filename,
- * then this was because an unescaped $ was seen. In this case, interpolate
- * the value of the environment variable that follows it into the output
- * filename.
- */
- if(nleft > 0) {
- char *value; /* The value of the environment variable */
- int vlen; /* The length of the value string */
- int nlen; /* The length of the environment variable name */
-/*
- * Read the name of the environment variable.
- */
- if(!cf_read_name(cf, "Environment", ++lptr, --nleft, cf->envnam, ENV_LEN))
- return 1;
-/*
- * Advance over the environment variable name in the input line.
- */
- nlen = strlen(cf->envnam);
- lptr += nlen;
- nleft -= nlen;
-/*
- * Get the value of the environment variable.
- */
- value = getenv(cf->envnam);
- if(!value) {
- const char *fmt = "Unknown environment variable: %.*s";
- sprintf(cf->errmsg, fmt, ERRLEN - strlen(fmt), cf->envnam);
- return 1;
- };
- vlen = strlen(value);
-/*
- * If we are at the start of the filename and the first character of the
- * environment variable value is a '~', attempt home-directory
- * interpolation.
- */
- if(cf->path->name[0] == '\0' && value[0] == '~') {
- if(!cf_read_name(cf, "User", value+1, vlen-1, cf->usrnam, USR_LEN) ||
- cf_expand_home_dir(cf, cf->usrnam))
- return 1;
-/*
- * If the home directory is the root directory, and the ~usrname expression
- * was followed by a directory separator, prevent the directory separator
- * from being appended to the root directory by skipping it in the
- * input line.
- */
- if(strcmp(cf->path->name, FS_ROOT_DIR) == 0 &&
- strncmp(lptr, FS_DIR_SEP, FS_DIR_SEP_LEN) == 0) {
- lptr += FS_DIR_SEP_LEN;
- nleft -= FS_DIR_SEP_LEN;
- };
- } else {
-/*
- * Append the value of the environment variable to the output path.
- */
- if(_pn_append_to_path(cf->path, value, strlen(value), escaped)==NULL) {
- strcpy(cf->errmsg, "Insufficient memory to complete filename");
- return 1;
- };
-/*
- * Prevent extra directory separators from being added.
- */
- if(nleft >= FS_DIR_SEP_LEN &&
- strcmp(cf->path->name, FS_ROOT_DIR) == 0 &&
- strncmp(lptr, FS_DIR_SEP, FS_DIR_SEP_LEN) == 0) {
- lptr += FS_DIR_SEP_LEN;
- nleft -= FS_DIR_SEP_LEN;
- } else if(vlen > FS_DIR_SEP_LEN &&
- strcmp(value + vlen - FS_DIR_SEP_LEN, FS_DIR_SEP)==0) {
- cf->path->name[vlen-FS_DIR_SEP_LEN] = '\0';
- };
- };
-/*
- * If adding the environment variable didn't form a valid directory,
- * we can't complete the line, since there is no way to separate append
- * a partial filename to an environment variable reference without
- * that appended part of the name being seen later as part of the
- * environment variable name. Thus if the currently constructed path
- * isn't a directory, quite now with no completions having been
- * registered.
- */
- if(!_pu_path_is_dir(cf->path->name))
- return 0;
-/*
- * For the reasons given above, if we have reached the end of the filename
- * with the expansion of an environment variable, the only allowed
- * completion involves the addition of a directory separator.
- */
- if(nleft == 0) {
- if(cpl_add_completion(cpl, line, lptr-line, word_end, FS_DIR_SEP,
- "", "")) {
- strncpy(cf->errmsg, cpl_last_error(cpl), ERRLEN);
- cf->errmsg[ERRLEN] = '\0';
- return 1;
- };
- return 0;
- };
- };
- };
-/*
- * Complete the filename if possible.
- */
- return cf_complete_entry(cf, cpl, line, word_start, word_end, escaped,
- check_fn, check_data);
-}
-
-/*.......................................................................
- * Return a description of the last path-completion error that occurred.
- *
- * Input:
- * cf CompleteFile * The path-completion resource object.
- * Output:
- * return const char * The description of the last error.
- */
-const char *_cf_last_error(CompleteFile *cf)
-{
- return cf ? cf->errmsg : "NULL CompleteFile argument";
-}
-
-/*.......................................................................
- * Lookup the home directory of the specified user, or the current user
- * if no name is specified, appending it to output pathname.
- *
- * Input:
- * cf CompleteFile * The pathname completion resource object.
- * user const char * The username to lookup, or "" to lookup the
- * current user.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-static int cf_expand_home_dir(CompleteFile *cf, const char *user)
-{
-/*
- * Attempt to lookup the home directory.
- */
- const char *home_dir = _hd_lookup_home_dir(cf->home, user);
-/*
- * Failed?
- */
- if(!home_dir) {
- strncpy(cf->errmsg, _hd_last_home_dir_error(cf->home), ERRLEN);
- cf->errmsg[ERRLEN] = '\0';
- return 1;
- };
-/*
- * Append the home directory to the pathname string.
- */
- if(_pn_append_to_path(cf->path, home_dir, -1, 0) == NULL) {
- strcpy(cf->errmsg, "Insufficient memory for home directory expansion");
- return 1;
- };
- return 0;
-}
-
-/*.......................................................................
- * Lookup and report all completions of a given username prefix.
- *
- * Input:
- * cf CompleteFile * The filename-completion resource object.
- * cpl WordCompletion * The object in which to record the completions.
- * prefix const char * The prefix of the usernames to lookup.
- * line const char * The command-line in which the username appears.
- * word_start int The index within line[] of the start of the
- * username that is being completed.
- * word_end int The index within line[] of the character which
- * follows the incomplete username.
- * escaped int True if the completions need to have special
- * characters escaped.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-static int cf_complete_username(CompleteFile *cf, WordCompletion *cpl,
- const char *prefix, const char *line,
- int word_start, int word_end, int escaped)
-{
-/*
- * Set up a container of anonymous arguments to be sent to the
- * username-lookup iterator.
- */
- CfHomeArgs args;
- args.cf = cf;
- args.cpl = cpl;
- args.prefix = prefix;
- args.line = line;
- args.word_start = word_start;
- args.word_end = word_end;
- args.escaped = escaped;
-/*
- * Iterate through the list of users, recording those which start
- * with the specified prefix.
- */
- if(_hd_scan_user_home_dirs(cf->home, &args, cf_homedir_callback)) {
- strncpy(cf->errmsg, _hd_last_home_dir_error(cf->home), ERRLEN);
- cf->errmsg[ERRLEN] = '\0';
- return 1;
- };
- return 0;
-}
-
-/*.......................................................................
- * The user/home-directory scanner callback function (see homedir.h)
- * used by cf_complete_username().
- */
-static HOME_DIR_FN(cf_homedir_callback)
-{
-/*
- * Get the file-completion resources from the anonymous data argument.
- */
- CfHomeArgs *args = (CfHomeArgs *) data;
- WordCompletion *cpl = args->cpl;
- CompleteFile *cf = args->cf;
-/*
- * Get the length of the username prefix.
- */
- int prefix_len = strlen(args->prefix);
-/*
- * Get the length of the latest user name that is to be compared to
- * the prefix.
- */
- int name_len = strlen(usrnam);
-/*
- * See if the latest username starts with the prefix that we are
- * searching for, and record its suffix in the array of matches if so.
- */
- if(name_len >= prefix_len && strncmp(args->prefix, usrnam, prefix_len)==0) {
-/*
- * Copy the username into the pathname work buffer, adding backslash
- * escapes where needed.
- */
- if(cf_prepare_suffix(cf, usrnam+prefix_len, args->escaped)) {
- strncpy(errmsg, cf->errmsg, maxerr);
- errmsg[maxerr] = '\0';
- return 1;
- };
-/*
- * Report the completion suffix that was copied above.
- */
- if(cpl_add_completion(cpl, args->line, args->word_start, args->word_end,
- cf->buff->name, FS_DIR_SEP, FS_DIR_SEP)) {
- strncpy(errmsg, cpl_last_error(cpl), maxerr);
- errmsg[maxerr] = '\0';
- return 1;
- };
- };
- return 0;
-}
-
-/*.......................................................................
- * Report possible completions of the filename in cf->path->name[].
- *
- * Input:
- * cf CompleteFile * The file-completion resource object.
- * cpl WordCompletion * The object in which to record the completions.
- * line const char * The input line, as received by the callback
- * function.
- * word_start int The index within line[] of the start of the
- * last component of the filename that is being
- * completed.
- * word_end int The index within line[] of the character which
- * follows the incomplete filename.
- * escaped int If true, escape special characters in the
- * completion suffixes.
- * check_fn CplCheckFn * If not zero, this argument specifies a
- * function to call to ask whether a given
- * file should be included in the list
- * of completions.
- * check_data void * Anonymous data to be passed to check_fn().
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-static int cf_complete_entry(CompleteFile *cf, WordCompletion *cpl,
- const char *line, int word_start, int word_end,
- int escaped, CplCheckFn *check_fn,
- void *check_data)
-{
- const char *dirpath; /* The name of the parent directory */
- int start; /* The index of the start of the last filename */
- /* component in the transcribed filename. */
- const char *prefix; /* The filename prefix to be completed */
- int prefix_len; /* The length of the filename prefix */
- const char *file_name; /* The lastest filename being compared */
- int waserr = 0; /* True after errors */
- int terminated=0; /* True if the directory part had to be terminated */
-/*
- * Get the pathname string and its current length.
- */
- char *pathname = cf->path->name;
- int pathlen = strlen(pathname);
-/*
- * Locate the start of the final component of the pathname.
- */
- for(start=pathlen - 1; start >= 0 &&
- strncmp(pathname + start, FS_DIR_SEP, FS_DIR_SEP_LEN) != 0; start--)
- ;
-/*
- * Is the parent directory the root directory?
- */
- if(start==0 ||
- (start < 0 && strncmp(pathname, FS_ROOT_DIR, FS_ROOT_DIR_LEN) == 0)) {
- dirpath = FS_ROOT_DIR;
- start += FS_ROOT_DIR_LEN;
-/*
- * If we found a directory separator then the part which precedes the
- * last component is the name of the directory to be opened.
- */
- } else if(start > 0) {
-/*
- * The _dr_open_dir() function requires the directory name to be '\0'
- * terminated, so temporarily do this by overwriting the first character
- * of the directory separator.
- */
- pathname[start] = '\0';
- dirpath = pathname;
- terminated = 1;
-/*
- * We reached the start of the pathname before finding a directory
- * separator, so arrange to open the current working directory.
- */
- } else {
- start = 0;
- dirpath = FS_PWD;
- };
-/*
- * Attempt to open the directory.
- */
- if(_dr_open_dir(cf->dr, dirpath, NULL)) {
- const char *fmt = "Can't open directory: %.*s";
- sprintf(cf->errmsg, fmt, ERRLEN - strlen(fmt), dirpath);
- return 1;
- };
-/*
- * If removed above, restore the directory separator and skip over it
- * to the start of the filename.
- */
- if(terminated) {
- memcpy(pathname + start, FS_DIR_SEP, FS_DIR_SEP_LEN);
- start += FS_DIR_SEP_LEN;
- };
-/*
- * Get the filename prefix and its length.
- */
- prefix = pathname + start;
- prefix_len = strlen(prefix);
-/*
- * Traverse the directory, looking for files who's prefixes match the
- * last component of the pathname.
- */
- while((file_name = _dr_next_file(cf->dr)) != NULL && !waserr) {
- int name_len = strlen(file_name);
-/*
- * Is the latest filename a possible completion of the filename prefix?
- */
- if(name_len >= prefix_len && strncmp(prefix, file_name, prefix_len)==0) {
-/*
- * When listing all files in a directory, don't list files that start
- * with '.'. This is how hidden files are denoted in UNIX.
- */
- if(prefix_len > 0 || file_name[0] != '.') {
-/*
- * Copy the completion suffix into the work pathname cf->buff->name,
- * adding backslash escapes if needed.
- */
- if(cf_prepare_suffix(cf, file_name + prefix_len, escaped)) {
- waserr = 1;
- } else {
-/*
- * We want directories to be displayed with directory suffixes,
- * and other fully completed filenames to be followed by spaces.
- * To check the type of the file, append the current suffix
- * to the path being completed, check the filetype, then restore
- * the path to its original form.
- */
- const char *cont_suffix = ""; /* The suffix to add if fully */
- /* completed. */
- const char *type_suffix = ""; /* The suffix to add when listing */
- if(_pn_append_to_path(cf->path, file_name + prefix_len,
- -1, escaped) == NULL) {
- strcpy(cf->errmsg, "Insufficient memory to complete filename.");
- return 1;
- };
-/*
- * Specify suffixes according to the file type.
- */
- if(_pu_path_is_dir(cf->path->name)) {
- cont_suffix = FS_DIR_SEP;
- type_suffix = FS_DIR_SEP;
- } else if(!check_fn || check_fn(check_data, cf->path->name)) {
- cont_suffix = " ";
- } else {
- cf->path->name[pathlen] = '\0';
- continue;
- };
-/*
- * Remove the temporarily added suffix.
- */
- cf->path->name[pathlen] = '\0';
-/*
- * Record the latest completion.
- */
- if(cpl_add_completion(cpl, line, word_start, word_end, cf->buff->name,
- type_suffix, cont_suffix))
- waserr = 1;
- };
- };
- };
- };
-/*
- * Close the directory.
- */
- _dr_close_dir(cf->dr);
- return waserr;
-}
-
-/*.......................................................................
- * Read a username or environment variable name, stopping when a directory
- * separator is seen, when the end of the string is reached, or the
- * output buffer overflows.
- *
- * Input:
- * cf CompleteFile * The file-completion resource object.
- * type char * The capitalized name of the type of name being read.
- * string char * The string who's prefix contains the name.
- * slen int The number of characters in string[].
- * nambuf char * The output name buffer.
- * nammax int The longest string that will fit in nambuf[], excluding
- * the '\0' terminator.
- * Output:
- * return char * A pointer to nambuf on success. On error NULL is
- * returned and a description of the error is recorded
- * in cf->errmsg[].
- */
-static char *cf_read_name(CompleteFile *cf, const char *type,
- const char *string, int slen,
- char *nambuf, int nammax)
-{
- int namlen; /* The number of characters in nambuf[] */
- const char *sptr; /* A pointer into string[] */
-/*
- * Work out the max number of characters that should be copied.
- */
- int nmax = nammax < slen ? nammax : slen;
-/*
- * Get the environment variable name that follows the dollar.
- */
- for(sptr=string,namlen=0;
- namlen < nmax && (slen-namlen < FS_DIR_SEP_LEN ||
- strncmp(sptr, FS_DIR_SEP, FS_DIR_SEP_LEN) != 0);
- namlen++) {
- nambuf[namlen] = *sptr++;
- };
-/*
- * Did the name overflow the buffer?
- */
- if(namlen >= nammax) {
- const char *fmt = "%.*s name too long";
- sprintf(cf->errmsg, fmt, ERRLEN - strlen(fmt), type);
- return NULL;
- };
-/*
- * Terminate the string.
- */
- nambuf[namlen] = '\0';
- return nambuf;
-}
-
-/*.......................................................................
- * Using the work buffer cf->buff, make a suitably escaped copy of a
- * given completion suffix, ready to be passed to cpl_add_completion().
- *
- * Input:
- * cf CompleteFile * The file-completion resource object.
- * suffix char * The suffix to be copied.
- * add_escapes int If true, escape special characters.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-static int cf_prepare_suffix(CompleteFile *cf, const char *suffix,
- int add_escapes)
-{
- const char *sptr; /* A pointer into suffix[] */
- int nbsl; /* The number of backslashes to add to the suffix */
- int i;
-/*
- * How long is the suffix?
- */
- int suffix_len = strlen(suffix);
-/*
- * Clear the work buffer.
- */
- _pn_clear_path(cf->buff);
-/*
- * Count the number of backslashes that will have to be added to
- * escape spaces, tabs, backslashes and wildcard characters.
- */
- nbsl = 0;
- if(add_escapes) {
- for(sptr = suffix; *sptr; sptr++) {
- switch(*sptr) {
- case ' ': case '\t': case '\\': case '*': case '?': case '[':
- nbsl++;
- break;
- };
- };
- };
-/*
- * Arrange for the output path buffer to have sufficient room for the
- * both the suffix and any backslashes that have to be inserted.
- */
- if(_pn_resize_path(cf->buff, suffix_len + nbsl) == NULL) {
- strcpy(cf->errmsg, "Insufficient memory to complete filename");
- return 1;
- };
-/*
- * If the suffix doesn't need any escapes, copy it directly into the
- * work buffer.
- */
- if(nbsl==0) {
- strcpy(cf->buff->name, suffix);
- } else {
-/*
- * Make a copy with special characters escaped?
- */
- if(nbsl > 0) {
- const char *src = suffix;
- char *dst = cf->buff->name;
- for(i=0; i<suffix_len; i++) {
- switch(*src) {
- case ' ': case '\t': case '\\': case '*': case '?': case '[':
- *dst++ = '\\';
- };
- *dst++ = *src++;
- };
- *dst = '\0';
- };
- };
- return 0;
-}