?? cplmatch.c
字號:
/* * 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;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -