⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcache.c

📁 xorp源码hg
💻 C
📖 第 1 页 / 共 4 页
字号:
    pc->tail = node;  } else {    pc->head = pc->tail = node;  };  return 0;}/*....................................................................... * Scan a given directory for files of interest, record their names * in mem->sg and append pointers to them to the mem->files[] array. * * Input: *  pc        PathCache *  The filename cache. *  dirname  const char *  The pathname of the directory to be scanned. *  mem        CacheMem *  The memory in which to store filenames of *                         interest. * Output: *  return          int    The number of files recorded, or -1 if a *                         memory error occurs. Note that the *                         inability to read the contents of the *                         directory is not counted as an error. */static int pca_scan_dir(PathCache *pc, const char *dirname, CacheMem *mem){  int nfile = 0;        /* The number of filenames recorded */  const char *filename; /* The name of the file being looked at *//* * Attempt to open the directory. If the directory can't be read then * there are no accessible files of interest in the directory. */  if(_dr_open_dir(pc->dr, dirname, NULL))    return 0;/* * Record the names of all files in the directory in the cache. */  while((filename = _dr_next_file(pc->dr))) {    char *copy;        /* A copy of the filename *//* * Make a temporary copy of the filename with an extra byte prepended. */    _pn_clear_path(pc->path);    if(_pn_append_to_path(pc->path, " ", 1, 0) == NULL ||       _pn_append_to_path(pc->path, filename, -1, 1) == NULL) {      strcpy(pc->errmsg, "Insufficient memory to record filename");      return -1;    };/* * Store the filename. */    copy = _sg_store_string(mem->sg, pc->path->name, 0);    if(!copy) {      strcpy(pc->errmsg, "Insufficient memory to cache file name.");      return -1;    };/* * Mark the filename as unchecked. */    copy[0] = PCA_F_ENIGMA;/* * Make room to store a pointer to the copy in mem->files[]. */    if(mem->nfiles + 1 > mem->files_dim) {      int needed = mem->files_dim + FILES_BLK_FACT;      char **files = (char **) realloc(mem->files, sizeof(*mem->files)*needed);      if(!files) {	strcpy(pc->errmsg, "Insufficient memory to extend filename cache.");	return 1;      };      mem->files = files;      mem->files_dim = needed;    };/* * Record a pointer to the copy of the filename at the end of the files[] * array. */    mem->files[mem->nfiles++] = copy;/* * Keep a record of the number of files matched so far. */    nfile++;  };/* * Sort the list of files into lexical order. */  qsort(mem->files + mem->nfiles - nfile, nfile, sizeof(*mem->files),	pca_cmp_matches);/* * Return the number of files recorded in mem->files[]. */  return nfile;}/*....................................................................... * A qsort() comparison function for comparing the cached filename * strings pointed to by two (char **) array elements. Note that * this ignores the initial cache-status byte of each filename. * * Input: *  v1, v2   void *  Pointers to the pointers of two strings to be compared. * Output: *  return    int    -1 -> v1 < v2. *                    0 -> v1 == v2 *                    1 -> v1 > v2 */static int pca_cmp_matches(const void *v1, const void *v2){  const char **s1 = (const char **) v1;  const char **s2 = (const char **) v2;  return strcmp(*s1+1, *s2+1);}/*....................................................................... * Given the simple name of a file, search the cached list of files * in the order in which they where found in the list of directories * previously presented to pca_scan_path(), and return the pathname * of the first file which has this name. If a pathname to a file is * given instead of a simple filename, this is returned without being * looked up in the cache, but with any initial ~username expression * expanded, and optionally, unescaped backslashes removed. * * Input: *  pc     PathCache *  The cached list of files. *  name  const char *  The name of the file to lookup. *  name_len     int    The length of the filename string at the *                      beginning of name[], or -1 to indicate that *                      the filename occupies the whole of the *                      string. *  literal      int    If this argument is zero, lone backslashes *                      in name[] are ignored during comparison *                      with filenames in the cache, under the *                      assumption that they were in the input line *                      soley to escape the special significance of *                      characters like spaces. To have them treated *                      as normal characters, give this argument a *                      non-zero value, such as 1. * Output: *  return      char *  The pathname of the first matching file, *                      or NULL if not found. Note that the returned *                      pointer points to memory owned by *pc, and *                      will become invalid on the next call to any *                      function in the PathCache module. */char *pca_lookup_file(PathCache *pc, const char *name, int name_len,		      int literal){  PathNode *node;   /* A node in the list of directories in the path */  char **match;     /* A pointer to a matching filename string in the cache *//* * Check the arguments. */  if(!pc || !name || name_len==0)    return NULL;/* * If no length was specified, determine the length of the string to * be looked up. */  if(name_len < 0)    name_len = strlen(name);/* * If the word starts with a ~username expression, the root directory, * of it contains any directory separators, then treat it isn't a simple * filename that can be looked up in the cache, but rather appears to * be the pathname of a file. If so, return a copy of this pathname with * escapes removed, if requested, and any initial ~username expression * expanded. */  if(cpa_cmd_contains_path(name, name_len)) {    const char *nptr;    if(pca_expand_tilde(pc, name, name_len, literal, &nptr) ||        _pn_append_to_path(pc->path, nptr, name_len - (nptr-name),			  !literal) == NULL)      return NULL;    return pc->path->name;  };/* * Look up the specified filename in each of the directories of the path, * in the same order that they were listed in the path, and stop as soon * as an instance of the file is found. */  for(node=pc->head; node; node=node->next) {/* * If the directory of the latest node is a relative pathname, * scan it for files of interest. */    if(node->relative) {      rst_CacheMem(node->mem);      if(pca_scan_dir(pc, node->dir, node->mem) < 1)	continue;      node->files = node->mem->files;      node->nfile = node->mem->nfiles;    };/* * Copy the filename into a temporary buffer, while interpretting * escape characters if needed. */    _pn_clear_path(pc->path);    if(_pn_append_to_path(pc->path, name, name_len, !literal) == NULL)      return NULL;/* * Perform a binary search for the requested filename. */    match = (char **)bsearch(pc->path->name, node->files, node->nfile,		             sizeof(*node->files), pca_cmp_file);    if(match) {/* * Prepend the pathname in which the directory was found, which we have * guaranteed to end in a directory separator, to the located filename. */      if(_pn_prepend_to_path(pc->path, node->dir, -1, 0) == NULL)	return NULL;/* * Return the matching pathname unless it is rejected by the application. */      if(!pc->check_fn || (*match)[0] == PCA_F_WANTED ||	 ((*match)[0]==PCA_F_ENIGMA && pc->check_fn(pc->data, pc->path->name))){	(*match)[0] = PCA_F_WANTED;	return pc->path->name;      } else {	*(match)[0] = PCA_F_IGNORE;      };    };  };/* * File not found. */  return NULL;}/*....................................................................... * A qsort() comparison function for comparing a filename string to * a cached filename string pointed to by a (char **) array element. * This ignores the initial code byte at the start of the cached filename * string. * * Input: *  v1, v2   void *  Pointers to the pointers of two strings to be compared. * Output: *  return    int    -1 -> v1 < v2. *                    0 -> v1 == v2 *                    1 -> v1 > v2 */static int pca_cmp_file(const void *v1, const void *v2){  const char *file_name = (const char *) v1;  const char **cache_name = (const char **) v2;  return strcmp(file_name, *cache_name + 1);}/*....................................................................... * The PcaPathConf structure may have options added to it in the future. * To allow your application to be linked against a shared version of the * tecla library, without these additions causing your application to * crash, you should use new_PcaPathConf() to allocate such structures. * This will set all of the configuration options to their default values, * which you can then change before passing the structure to * pca_path_completions(). * * Input: *  pc         PathCache *  The filename cache in which to look for *                          file name completions. * Output: *  return   PcaPathConf *  The new configuration structure, or NULL *                          on error. A descripition of the error *                          can be found by calling pca_last_error(pc). */PcaPathConf *new_PcaPathConf(PathCache *pc){  PcaPathConf *ppc;  /* The object to be returned *//* * Check the arguments. */  if(!pc)    return NULL;/* * Allocate the container. */  ppc = (PcaPathConf *)malloc(sizeof(PcaPathConf));  if(!ppc) {    strcpy(pc->errmsg, "Insufficient memory.");    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_PcaPathConf(). */  if(pca_init_PcaPathConf(ppc, pc))    return del_PcaPathConf(ppc);  return ppc;}/*....................................................................... * Initialize a PcaPathConf configuration structure with defaults. * * Input: *  ppc   PcaPathConf *  The structre to be initialized. *  pc      PathCache *  The cache in which completions will be looked up. * Output: *  return        int    0 - OK. *                       1 - Error. A description of the error can be *                           obtained by calling pca_last_error(pc). */static int pca_init_PcaPathConf(PcaPathConf *ppc, PathCache *pc){/* * Check the arguments. */  if(!pc)    return 1;/* * Set the default options. */  ppc->id = PPC_ID_CODE;  ppc->pc = pc;  ppc->escaped = 1;  ppc->file_start = -1;  return 0;}/*....................................................................... * Delete a PcaPathConf object. * * Input: *  ppc    PcaPathConf *  The object to be deleted. * Output: *  return PcaPathConf *  The deleted object (always NULL). */PcaPathConf *del_PcaPathConf(PcaPathConf *ppc){  if(ppc) {    ppc->pc = NULL;  /* It is up to the caller to delete the cache *//* * Delete the container. */    free(ppc);  };  return NULL;}/*....................................................................... * pca_path_completions() is a completion callback function for use * directly with cpl_complete_word() or gl_customize_completions(), or * indirectly from your own completion callback function. It requires * that a CpaPathArgs object be passed via its 'void *data' argument. */CPL_MATCH_FN(pca_path_completions){  PcaPathConf *ppc;       /* The configuration arguments */  PathCache *pc;          /* The cache in which to look for completions */  PathNode *node;         /* A node in the list of directories in the path */  const char *filename;   /* The name of the file being looked at */  const char *start_path; /* The pointer to the start of the pathname */                          /*  in line[]. */  int word_start;         /* The index in line[] corresponding to start_path */  const char *prefix;     /* The file-name prefix being searched for */  size_t prefix_len;      /* The length of the prefix being completed */  int bot;                /* The lowest index of the array not searched yet */  int top;                /* The highest index of the array not searched yet *//* * Check the arguments. */  if(!cpl)    return 1;  if(!line || word_end < 0 || !data) {    cpl_record_error(cpl, "pca_path_completions: Invalid arguments.");    return 1;  };/* * Get the configuration arguments. */  ppc = (PcaPathConf *) data;/* * Check that the callback data is a PcaPathConf structure returned * by new_PcaPathConf(). */  if(ppc->id != PPC_ID_CODE) {    cpl_record_error(cpl,		     "Invalid callback data passed to pca_path_completions()");    return 1;  };/* * Get the filename cache. */  pc = ppc->pc;/* * Get the start of the file name. 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(ppc->file_start < 0) {    start_path = _pu_start_of_path(line, word_end);    if(!start_path) {      cpl_record_error(cpl, "Unable to find the start of the file name.");      return 1;    };  } else {    start_path = line + ppc->file_start;  };/* * Get the index of the start of the word being completed. */  word_start = start_path - line;/* * Work out the length of the prefix that is bein completed. */  prefix_len = word_end - word_start;/* * If the word starts with a ~username expression or the root directory, * of it contains any directory separators, then completion must be * delegated to cpl_file_completions(). */  if(cpa_cmd_contains_path(start_path, prefix_len)) {    cfc_file_start(pc->cfc, word_start);    return cpl_file_completions(cpl, pc->cfc, line, word_end);  };/* * Look up the specified file name in each of the directories of the path, * in the same order that they were listed in the path, and stop as soon * as an instance of the file is found. */  for(node=pc->head; node; node=node->next) {/* * If the directory of the latest node is a relative pathname,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -