diff options
Diffstat (limited to 'libtecla-1.4.1/cplmatch.c')
-rw-r--r-- | libtecla-1.4.1/cplmatch.c | 927 |
1 files changed, 0 insertions, 927 deletions
diff --git a/libtecla-1.4.1/cplmatch.c b/libtecla-1.4.1/cplmatch.c deleted file mode 100644 index 111f5bd..0000000 --- a/libtecla-1.4.1/cplmatch.c +++ /dev/null @@ -1,927 +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 <stdlib.h> -#include <stdio.h> -#include <string.h> - -/* - * Local includes. - */ -#include "libtecla.h" -#include "stringrp.h" -#include "pathutil.h" -#include "cplfile.h" - -/* - * Specify the number of strings to allocate when the string free-list - * is exhausted. This also sets the number of elements to expand the - * matches[] array by whenever it is found to be too small. - */ -#define STR_BLK_FACT 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 don't decrease it below 80. - */ -#define ERRLEN 200 - -/* - * Completion matches are recorded in containers of the following - * type. - */ -struct WordCompletion { - StringGroup *sg; /* Memory for a group of strings */ - int matches_dim; /* The allocated size of result.matches[] */ - char errmsg[ERRLEN+1]; /* The error-reporting buffer */ - CplMatches result; /* Completions to be returned to the caller */ - CompleteFile *cf; /* The resources used for filename completion */ -}; - -static void cpl_sort_matches(WordCompletion *cpl); -static void cpl_zap_duplicates(WordCompletion *cpl); -static void cpl_clear_completions(WordCompletion *cpl); -static int cpl_cmp_matches(const void *v1, const void *v2); -static int cpl_cmp_suffixes(const void *v1, const void *v2); - -/* - * The new_CplFileConf() constructor sets the integer first member of - * the returned object to the following magic number. On seeing this, - * cpl_file_completions() knows when it is passed a valid CplFileConf - * object. - */ -#define CFC_ID_CODE 4568 - -/* - * A pointer to a structure of the following type can be passed to - * the builtin file-completion callback function to modify its behavior. - */ -struct CplFileConf { - int id; /* new_CplFileConf() sets this to CFC_ID_CODE */ - int escaped; /* If none-zero, backslashes in the input line are */ - /* interpreted as escaping special characters and */ - /* spaces, and any special characters and spaces in */ - /* the listed completions will also be escaped with */ - /* added backslashes. This is the default behaviour. */ - /* If zero, backslashes are interpreted as being */ - /* literal parts of the filename, and none are added */ - /* to the completion suffixes. */ - int file_start; /* The index in the input line of the first character */ - /* of the filename. If you specify -1 here, */ - /* cpl_file_completions() identifies the */ - /* the start of the filename by looking backwards for */ - /* an unescaped space, or the beginning of the line. */ - CplCheckFn *chk_fn; /* If not zero, this argument specifies a */ - /* function to call to ask whether a given */ - /* file should be included in the list */ - /* of completions. */ - void *chk_data; /* Anonymous data to be passed to check_fn(). */ -}; - -static void cpl_init_FileConf(CplFileConf *cfc); - -/*....................................................................... - * Create a new string-completion object. - * - * Output: - * return WordCompletion * The new object, or NULL on error. - */ -WordCompletion *new_WordCompletion(void) -{ - WordCompletion *cpl; /* The object to be returned */ -/* - * Allocate the container. - */ - cpl = (WordCompletion *) malloc(sizeof(WordCompletion)); - if(!cpl) { - fprintf(stderr, "new_WordCompletion: 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_WordCompletion(). - */ - cpl->sg = NULL; - cpl->matches_dim = 0; - cpl->result.suffix = NULL; - cpl->result.cont_suffix = NULL; - cpl->result.matches = NULL; - cpl->result.nmatch = 0; - cpl->cf = NULL; -/* - * Allocate an object that allows a group of strings to be allocated - * efficiently by placing many of them in contiguous string segments. - */ - cpl->sg = _new_StringGroup(_pu_pathname_dim()); - if(!cpl->sg) - return del_WordCompletion(cpl); -/* - * Allocate an array for matching completions. This will be extended later - * if needed. - */ - cpl->matches_dim = STR_BLK_FACT; - cpl->result.matches = (CplMatch *) malloc(sizeof(cpl->result.matches[0]) * - cpl->matches_dim); - if(!cpl->result.matches) { - fprintf(stderr, - "new_WordCompletion: Insufficient memory to allocate array of matches.\n"); - return del_WordCompletion(cpl); - }; -/* - * Allocate a filename-completion resource object. - */ - cpl->cf = _new_CompleteFile(); - if(!cpl->cf) - return del_WordCompletion(cpl); - return cpl; -} - -/*....................................................................... - * Delete a string-completion object. - * - * Input: - * cpl WordCompletion * The object to be deleted. - * Output: - * return WordCompletion * The deleted object (always NULL). - */ -WordCompletion *del_WordCompletion(WordCompletion *cpl) -{ - if(cpl) { - cpl->sg = _del_StringGroup(cpl->sg); - if(cpl->result.matches) { - free(cpl->result.matches); - cpl->result.matches = NULL; - cpl->cf = _del_CompleteFile(cpl->cf); - }; - free(cpl); - }; - return NULL; -} - -/*....................................................................... - * This function is designed to be called by CplMatchFn callback - * functions. It adds one possible completion of the token that is being - * completed to an array of completions. If the completion needs any - * special quoting to be valid when displayed in the input line, this - * quoting must be included in the string. - * - * Input: - * cpl WordCompletion * The argument of the same name that was passed - * to the calling CplMatchFn callback function. - * line const char * The input line, as received by the callback - * function. - * word_start int The index within line[] of the start of the - * word that is being completed. - * word_end int The index within line[] of the character which - * follows the incomplete word, as received by the - * calling callback function. - * suffix const char * The appropriately quoted string that could - * be appended to the incomplete token to complete - * it. A copy of this string will be allocated - * internally. - * type_suffix const char * When listing multiple completions, gl_get_line() - * appends this string to the completion to indicate - * its type to the user. If not pertinent pass "". - * Otherwise pass a literal or static string. - * cont_suffix const char * If this turns out to be the only completion, - * gl_get_line() will append this string as - * a continuation. For example, the builtin - * file-completion callback registers a directory - * separator here for directory matches, and a - * space otherwise. If the match were a function - * name you might want to append an open - * parenthesis, etc.. If not relevant pass "". - * Otherwise pass a literal or static string. - * Output: - * return int 0 - OK. - * 1 - Error. - */ -int cpl_add_completion(WordCompletion *cpl, const char *line, - int word_start, int word_end, const char *suffix, - const char *type_suffix, const char *cont_suffix) -{ - CplMatch *match; /* The container of the new match */ - char *string; /* A newly allocated copy of the completion string */ -/* - * Check the arguments. - */ - if(!cpl) - return 1; - if(!suffix) - return 0; - if(!type_suffix) - type_suffix = ""; - if(!cont_suffix) - cont_suffix = ""; -/* - * Do we need to extend the array of matches[]? - */ - if(cpl->result.nmatch+1 > cpl->matches_dim) { - int needed = cpl->matches_dim + STR_BLK_FACT; - CplMatch *matches = (CplMatch *) realloc(cpl->result.matches, - sizeof(cpl->result.matches[0]) * needed); - if(!matches) { - strcpy(cpl->errmsg, "Insufficient memory to extend array of matches."); - return 1; - }; - cpl->result.matches = matches; - cpl->matches_dim = needed; - }; -/* - * Allocate memory to store the combined completion prefix and the - * new suffix. - */ - string = _sg_alloc_string(cpl->sg, word_end-word_start + strlen(suffix)); - if(!string) { - strcpy(cpl->errmsg, "Insufficient memory to extend array of matches."); - return 1; - }; -/* - * Compose the string. - */ - strncpy(string, line + word_start, word_end - word_start); - strcpy(string + word_end - word_start, suffix); -/* - * Record the new match. - */ - match = cpl->result.matches + cpl->result.nmatch++; - match->completion = string; - match->suffix = string + word_end - word_start; - match->type_suffix = type_suffix; -/* - * Record the continuation suffix. - */ - cpl->result.cont_suffix = cont_suffix; - return 0; -} - -/*....................................................................... - * Sort the array of matches. - * - * Input: - * cpl WordCompletion * The completion resource object. - */ -static void cpl_sort_matches(WordCompletion *cpl) -{ - qsort(cpl->result.matches, cpl->result.nmatch, - sizeof(cpl->result.matches[0]), cpl_cmp_matches); -} - -/*....................................................................... - * This is a qsort() comparison function used to sort matches. - * - * Input: - * v1, v2 void * Pointers to the two matches to be compared. - * Output: - * return int -1 -> v1 < v2. - * 0 -> v1 == v2 - * 1 -> v1 > v2 - */ -static int cpl_cmp_matches(const void *v1, const void *v2) -{ - const CplMatch *m1 = (const CplMatch *) v1; - const CplMatch *m2 = (const CplMatch *) v2; - return strcmp(m1->completion, m2->completion); -} - -/*....................................................................... - * Sort the array of matches in order of their suffixes. - * - * Input: - * cpl WordCompletion * The completion resource object. - */ -static void cpl_sort_suffixes(WordCompletion *cpl) -{ - qsort(cpl->result.matches, cpl->result.nmatch, - sizeof(cpl->result.matches[0]), cpl_cmp_suffixes); -} - -/*....................................................................... - * This is a qsort() comparison function used to sort matches in order of - * their suffixes. - * - * Input: - * v1, v2 void * Pointers to the two matches to be compared. - * Output: - * return int -1 -> v1 < v2. - * 0 -> v1 == v2 - * 1 -> v1 > v2 - */ -static int cpl_cmp_suffixes(const void *v1, const void *v2) -{ - const CplMatch *m1 = (const CplMatch *) v1; - const CplMatch *m2 = (const CplMatch *) v2; - return strcmp(m1->suffix, m2->suffix); -} - -/*....................................................................... - * Find the common prefix of all of the matching completion matches, - * and record a pointer to it in cpl->result.suffix. Note that this has - * the side effect of sorting the matches into suffix order. - * - * Input: - * cpl WordCompletion * The completion resource object. - * Output: - * return int 0 - OK. - * 1 - Error. - */ -static int cpl_common_suffix(WordCompletion *cpl) -{ - CplMatches *result; /* The result container */ - const char *first, *last; /* The first and last matching suffixes */ - int length; /* The length of the common suffix */ -/* - * Get the container of the array of matching files. - */ - result = &cpl->result; -/* - * No matching completions? - */ - if(result->nmatch < 1) - return 0; -/* - * Sort th matches into suffix order. - */ - cpl_sort_suffixes(cpl); -/* - * Given that the array of matches is sorted, the first and last - * suffixes are those that differ most in their prefixes, so the common - * prefix of these strings is the longest common prefix of all of the - * suffixes. - */ - first = result->matches[0].suffix; - last = result->matches[result->nmatch - 1].suffix; -/* - * Find the point at which the first and last matching strings - * first difffer. - */ - while(*first && *first == *last) { - first++; - last++; - }; -/* - * How long is the common suffix? - */ - length = first - result->matches[0].suffix; -/* - * Allocate memory to record the common suffix. - */ - result->suffix = _sg_alloc_string(cpl->sg, length); - if(!result->suffix) { - strcpy(cpl->errmsg, - "Insufficient memory to record common completion suffix."); - return 1; - }; -/* - * Record the common suffix. - */ - strncpy(result->suffix, result->matches[0].suffix, length); - result->suffix[length] = '\0'; - return 0; -} - -/*....................................................................... - * Discard the contents of the array of possible completion matches. - * - * Input: - * cpl WordCompletion * The word-completion resource object. - */ -static void cpl_clear_completions(WordCompletion *cpl) -{ -/* - * Discard all of the strings. - */ - _clr_StringGroup(cpl->sg); -/* - * Record the fact that the array is now empty. - */ - cpl->result.nmatch = 0; - cpl->result.suffix = NULL; - cpl->result.cont_suffix = ""; -/* - * Also clear the error message. - */ - cpl->errmsg[0] = '\0'; - return; -} - -/*....................................................................... - * Given an input line and the point at which it completion is to be - * attempted, return an array of possible completions. - * - * Input: - * cpl WordCompletion * The completion resource object. - * line char * The current input line. - * word_end int The index of the character in line[] which - * follows the end of the token that is being - * completed. - * data void * Anonymous 'data' to be passed to match_fn(). - * match_fn CplMatchFn * The function that will identify the prefix - * to be completed from the input line, and - * record completion matches. - * Output: - * return CplMatches * The container of the array of possible - * completions. The returned pointer refers - * to a container owned by the parent WordCompletion - * object, and its contents thus potentially - * change on every call to cpl_matches(). - * On error, NULL is returned, and a description - * of the error can be acquired by calling - * cpl_last_error(cpl). - */ -CplMatches *cpl_complete_word(WordCompletion *cpl, const char *line, - int word_end, void *data, - CplMatchFn *match_fn) -{ - int line_len; /* The total length of the input line */ -/* - * How long is the input line? - */ - line_len = strlen(line); -/* - * Check the arguments. - */ - if(!cpl || !line || !match_fn || word_end < 0 || word_end > line_len) { - if(cpl) - strcpy(cpl->errmsg, "cpl_complete_word: Invalid arguments."); - return NULL; - }; -/* - * Clear the return container. - */ - cpl_clear_completions(cpl); -/* - * Have the matching function record possible completion matches in - * cpl->result.matches. - */ - if(match_fn(cpl, data, line, word_end)) { - if(cpl->errmsg[0] == '\0') - strcpy(cpl->errmsg, "Error completing word."); - return NULL; - }; -/* - * Record a copy of the common initial part of all of the prefixes - * in cpl->result.common. - */ - if(cpl_common_suffix(cpl)) - return NULL; -/* - * Sort the matches into lexicographic order. - */ - cpl_sort_matches(cpl); -/* - * Discard any duplicate matches. - */ - cpl_zap_duplicates(cpl); -/* - * If there is more than one match, discard the continuation suffix. - */ - if(cpl->result.nmatch > 1) - cpl->result.cont_suffix = ""; -/* - * Return the array of matches. - */ - return &cpl->result; -} - -/*....................................................................... - * Print out an array of matching completions. - * - * Input: - * result CplMatches * The container of the sorted array of - * completions. - * fp FILE * The output stream to write to. - * term_width int The width of the terminal. - * Output: - * return int 0 - OK. - * 1 - Error. - */ -int cpl_list_completions(CplMatches *result, FILE *fp, int term_width) -{ - int maxlen; /* The length of the longest matching string */ - int width; /* The width of a column */ - int ncol; /* The number of columns to list */ - int nrow; /* The number of rows needed to list all of the matches */ - int row,col; /* The row and column being written to */ - int i; -/* - * Check the arguments. - */ - if(!result || !fp) { - fprintf(stderr, "cpl_list_completions: NULL argument(s).\n"); - return 1; - }; -/* - * Not enough space to list anything? - */ - if(term_width < 1) - return 0; -/* - * Work out the maximum length of the matching strings. - */ - maxlen = 0; - for(i=0; i<result->nmatch; i++) { - CplMatch *match = result->matches + i; - int len = strlen(match->completion) + - strlen(match->type_suffix); - if(len > maxlen) - maxlen = len; - }; -/* - * Nothing to list? - */ - if(maxlen == 0) - return 0; -/* - * Split the available terminal width into columns of maxlen + 2 characters. - */ - width = maxlen + 2; - ncol = term_width / width; -/* - * If the column width is greater than the terminal width, the matches will - * just have to overlap onto the next line. - */ - if(ncol < 1) - ncol = 1; -/* - * How many rows will be needed? - */ - nrow = (result->nmatch + ncol - 1) / ncol; -/* - * Print the matches out in ncol columns, sorted in row order within each - * column. - */ - for(row=0; row < nrow; row++) { - for(col=0; col < ncol; col++) { - int m = col*nrow + row; - if(m < result->nmatch) { - CplMatch *match = result->matches + m; - if(fprintf(fp, "%s%-*s%s", match->completion, - (int) (ncol > 1 ? maxlen - strlen(match->completion):0), - match->type_suffix, col<ncol-1 ? " " : "\r\n") < 0) - return 1; - } else { - if(fprintf(fp, "\r\n") < 0) - return 1; - break; - }; - }; - }; - return 0; -} - -/*....................................................................... - * Return a description of the string-completion error that occurred. - * - * Input: - * cpl WordCompletion * The string-completion resource object. - * Output: - * return const char * The description of the last error. - */ -const char *cpl_last_error(WordCompletion *cpl) -{ - return cpl ? cpl->errmsg : "NULL WordCompletion argument"; -} - -/*....................................................................... - * When an error occurs while performing a completion, you registerf a - * terse description of the error by calling cpl_record_error(). This - * message will then be returned on the next call to cpl_last_error(). - * - * Input: - * cpl WordCompletion * The string-completion resource object that was - * originally passed to the callback. - * errmsg const char * The description of the error. - */ -void cpl_record_error(WordCompletion *cpl, const char *errmsg) -{ - if(cpl && errmsg) { - strncpy(cpl->errmsg, errmsg, ERRLEN); - cpl->errmsg[ERRLEN] = '\0'; - }; -} - -/*....................................................................... - * This is the builtin completion callback function which performs file - * completion. - * - * Input: - * cpl WordCompletion * An opaque pointer to the object that will - * contain the matches. This should be filled - * via zero or more calls to cpl_add_completion(). - * data void * Either NULL to request the default - * file-completion behavior, or a pointer to a - * CplFileConf structure, whose members specify - * a different behavior. - * line char * The current input line. - * word_end int The index of the character in line[] which - * follows the end of the token that is being - * completed. - * Output - * return int 0 - OK. - * 1 - Error. - */ -CPL_MATCH_FN(cpl_file_completions) -{ - const char *start_path; /* The pointer to the start of the pathname */ - /* in line[]. */ - CplFileConf *conf; /* The new-style configuration object. */ -/* - * The following configuration object will be used if the caller didn't - * provide one. - */ - CplFileConf default_conf; -/* - * This function can be called externally, so check its arguments. - */ - if(!cpl) - return 1; - if(!line || word_end < 0) { - strcpy(cpl->errmsg, "cpl_file_completions: Invalid arguments."); - return 1; - }; -/* - * The 'data' argument is either a CplFileConf pointer, identifiable - * by having an integer id code as its first member, or the deprecated - * CplFileArgs pointer, or can be NULL to request the default - * configuration. - */ - if(data && *(int *)data == CFC_ID_CODE) { - conf = (CplFileConf *) data; - } else { -/* - * Select the defaults. - */ - conf = &default_conf; - cpl_init_FileConf(&default_conf); -/* - * If we have been passed an instance of the deprecated CplFileArgs - * structure, copy its configuration parameters over the defaults. - */ - if(data) { - CplFileArgs *args = (CplFileArgs *) data; - conf->escaped = args->escaped; - conf->file_start = args->file_start; - }; - }; -/* - * Get the start of the filename. If not specified by the caller - * identify it by searching backwards in the input line for an - * unescaped space or the start of the line. - */ - if(conf->file_start < 0) { - start_path = _pu_start_of_path(line, word_end); - if(!start_path) { - strcpy(cpl->errmsg, "Unable to find the start of the filename."); - return 1; - }; - } else { - start_path = line + conf->file_start; - }; -/* - * Perform the completion. - */ - if(_cf_complete_file(cpl, cpl->cf, line, start_path - line, word_end, - conf->escaped, conf->chk_fn, conf->chk_data)) { - cpl_record_error(cpl, _cf_last_error(cpl->cf)); - return 1; - }; - return 0; -} - -/*....................................................................... - * Initialize a CplFileArgs structure with default configuration - * parameters. Note that the CplFileArgs configuration type is - * deprecated. The opaque CplFileConf object should be used in future - * applications. - * - * Input: - * cfa CplFileArgs * The configuration object of the - * cpl_file_completions() callback. - */ -void cpl_init_FileArgs(CplFileArgs *cfa) -{ - if(cfa) { - cfa->escaped = 1; - cfa->file_start = -1; - }; -} - -/*....................................................................... - * Initialize a CplFileConf structure with default configuration - * parameters. - * - * Input: - * cfc CplFileConf * The configuration object of the - * cpl_file_completions() callback. - */ -static void cpl_init_FileConf(CplFileConf *cfc) -{ - if(cfc) { - cfc->id = CFC_ID_CODE; - cfc->escaped = 1; - cfc->file_start = -1; - cfc->chk_fn = 0; - cfc->chk_data = NULL; - }; -} - -/*....................................................................... - * Create a new CplFileConf object and initialize it with defaults. - * - * Output: - * return CplFileConf * The new object, or NULL on error. - */ -CplFileConf *new_CplFileConf(void) -{ - CplFileConf *cfc; /* The object to be returned */ -/* - * Allocate the container. - */ - cfc = (CplFileConf *)malloc(sizeof(CplFileConf)); - if(!cfc) - 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_CplFileConf(). - */ - cpl_init_FileConf(cfc); - return cfc; -} - -/*....................................................................... - * Delete a CplFileConf object. - * - * Input: - * cfc CplFileConf * The object to be deleted. - * Output: - * return CplFileConf * The deleted object (always NULL). - */ -CplFileConf *del_CplFileConf(CplFileConf *cfc) -{ - if(cfc) { -/* - * Delete the container. - */ - free(cfc); - }; - return NULL; -} - -/*....................................................................... - * If backslashes in the filename should be treated as literal - * characters, call the following function with literal=1. Otherwise - * the default is to treat them as escape characters, used for escaping - * spaces etc.. - * - * Input: - * cfc CplFileConf * The cpl_file_completions() configuration object - * to be configured. - * literal int Pass non-zero here to enable literal interpretation - * of backslashes. Pass 0 to turn off literal - * interpretation. - */ -void cfc_literal_escapes(CplFileConf *cfc, int literal) -{ - if(cfc) - cfc->escaped = !literal; -} - -/*....................................................................... - * Call this function if you know where the index at which the - * filename prefix starts in the input line. Otherwise by default, - * or if you specify start_index to be -1, the filename is taken - * to start after the first unescaped space preceding the cursor, - * or the start of the line, which ever comes first. - * - * Input: - * cfc CplFileConf * The cpl_file_completions() configuration object - * to be configured. - * start_index int The index of the start of the filename in - * the input line, or -1 to select the default. - */ -void cfc_file_start(CplFileConf *cfc, int start_index) -{ - if(cfc) - cfc->file_start = start_index; -} - -/*....................................................................... - * If you only want certain types of files to be included in the - * list of completions, you use the following function to specify a - * callback function which will be called to ask whether a given file - * should be included. - * - * Input: - * cfc CplFileConf * The cpl_file_completions() configuration object - * to be configured. - * chk_fn CplCheckFn * Zero to disable filtering, or a pointer to a - * function that returns 1 if a given file should - * be included in the list of completions. - * chk_data void * Anonymous data to be passed to chk_fn() - * every time that it is called. - */ -void cfc_set_check_fn(CplFileConf *cfc, CplCheckFn *chk_fn, void *chk_data) -{ - if(cfc) { - cfc->chk_fn = chk_fn; - cfc->chk_data = chk_data; - }; -} - -/*....................................................................... - * The following CplCheckFn callback returns non-zero if the specified - * filename is that of an executable. - */ -CPL_CHECK_FN(cpl_check_exe) -{ - return _pu_path_is_exe(pathname); -} - -/*....................................................................... - * Remove duplicates from a sorted array of matches. - * - * Input: - * cpl WordCompletion * The completion resource object. - */ -static void cpl_zap_duplicates(WordCompletion *cpl) -{ - CplMatch *matches; /* The array of matches */ - int nmatch; /* The number of elements in matches[] */ - const char *completion; /* The completion string of the last unique match */ - const char *type_suffix; /* The type of the last unique match */ - int src; /* The index of the match being considered */ - int dst; /* The index at which to record the next */ - /* unique match. */ -/* - * Get the array of matches and the number of matches that it - * contains. - */ - matches = cpl->result.matches; - nmatch = cpl->result.nmatch; -/* - * No matches? - */ - if(nmatch < 1) - return; -/* - * Initialize the comparison strings with the first match. - */ - completion = matches[0].completion; - type_suffix = matches[0].type_suffix; -/* - * Go through the array of matches, copying each new unrecorded - * match at the head of the array, while discarding duplicates. - */ - for(src=dst=1; src<nmatch; src++) { - CplMatch *match = matches + src; - if(strcmp(completion, match->completion) != 0 || - strcmp(type_suffix, match->type_suffix) != 0) { - if(src != dst) - matches[dst] = *match; - dst++; - completion = match->completion; - type_suffix = match->type_suffix; - }; - }; -/* - * Record the number of unique matches that remain. - */ - cpl->result.nmatch = dst; - return; -} |