📄 pcache.c
字号:
if(check_fn != pc->check_fn || data != pc->data) pca_remove_marks(pc);/* * Record the new callback locally. */ pc->check_fn = check_fn; pc->data = data;/* * Configure cpl_file_completions() to use the same callback to * select files of interest. */ cfc_set_check_fn(pc->cfc, check_fn, data); }; return;}/*....................................................................... * Return a description of the last path-caching error that occurred. * * Input: * pc PathCache * The filename cache that suffered the error. * Output: * return char * The description of the last error. */const char *pca_last_error(PathCache *pc){ return pc ? pc->errmsg : "NULL PathCache argument";}/*....................................................................... * Discard all cached filenames. * * Input: * pc PathCache * The cache to be cleared. */static void pca_clear_cache(PathCache *pc){ if(pc) {/* * Return all path-nodes to the freelist. */ _rst_FreeList(pc->node_mem); pc->head = pc->tail = NULL;/* * Delete all filename strings. */ rst_CacheMem(pc->abs_mem); rst_CacheMem(pc->rel_mem); }; return;}/*....................................................................... * Build the list of files of interest contained in a given * colon-separated list of directories. * * Input: * pc PathCache * The cache in which to store the names of * the files that are found in the list of * directories. * path const char * A colon-separated list of directory * paths. Under UNIX, when searching for * executables, this should be the return * value of getenv("PATH"). * Output: * return int 0 - OK. * 1 - An error occurred. A description of * the error can be acquired by calling * pca_last_error(pc). */int pca_scan_path(PathCache *pc, const char *path){ const char *pptr; /* A pointer to the next unprocessed character in path[] */ PathNode *node; /* A node in the list of directory paths */ char **fptr; /* A pointer into pc->abs_mem->files[] *//* * Check the arguments. */ if(!pc) return 1;/* * Clear the outdated contents of the cache. */ pca_clear_cache(pc);/* * If no path list was provided, there is nothing to be added to the * cache. */ if(!path) return 0;/* * Extract directories from the path list, expanding tilde expressions * on the fly into pc->pathname, then add them to the list of path * nodes, along with a sorted list of the filenames of interest that * the directories hold. */ pptr = path; while(*pptr) {/* * Extract the next pathname component into pc->path->name. */ if(pca_extract_dir(pc, pptr, &pptr)) return 1;/* * Add a new node to the list of paths, containing both the * directory name and, if not a relative pathname, the list of * files of interest in the directory. */ if(add_PathNode(pc, pc->path->name)) return 1; };/* * The file arrays in each absolute directory node are sections of * pc->abs_mem->files[]. Record pointers to the starts of each * of these sections in each directory node. Note that this couldn't * be done in add_PathNode(), because pc->abs_mem->files[] may * get reallocated in subsequent calls to add_PathNode(), thus * invalidating any pointers to it. */ fptr = pc->abs_mem->files; for(node=pc->head; node; node=node->next) { node->files = fptr; fptr += node->nfile; }; return 0;}/*....................................................................... * Extract the next directory path from a colon-separated list of * directories, expanding tilde home-directory expressions where needed. * * Input: * pc PathCache * The cache of filenames. * path const char * A pointer to the start of the next component * in the path list. * Input/Output: * nextp const char ** A pointer to the next unprocessed character * in path[] will be assigned to *nextp. * Output: * return int 0 - OK. The extracted path is in pc->path->name. * 1 - Error. A description of the error will * have been left in pc->errmsg. */static int pca_extract_dir(PathCache *pc, const char *path, const char **nextp){ const char *pptr; /* A pointer into path[] */ const char *sptr; /* The path following tilde expansion */ int escaped = 0; /* True if the last character was a backslash *//* * If there is a tilde expression at the beginning of the specified path, * place the corresponding home directory into pc->path. Otherwise * just clear pc->path. */ if(pca_expand_tilde(pc, path, strlen(path), 0, &pptr)) return 1;/* * Keep a record of the current location in the path. */ sptr = pptr;/* * Locate the end of the directory name in the pathname string, stopping * when either the end of the string is reached, or an un-escaped colon * separator is seen. */ while(*pptr && (escaped || *pptr != ':')) escaped = !escaped && *pptr++ == '\\';/* * Append the rest of the directory path to the pathname buffer. */ if(_pn_append_to_path(pc->path, sptr, pptr - sptr, 1) == NULL) { strcpy(pc->errmsg, "Insufficient memory to record directory name"); return 1; };/* * To facilitate subsequently appending filenames to the directory * path name, make sure that the recorded directory name ends in a * directory separator. */ { int dirlen = strlen(pc->path->name); if(dirlen < FS_DIR_SEP_LEN || strncmp(pc->path->name + dirlen - FS_DIR_SEP_LEN, FS_DIR_SEP, FS_DIR_SEP_LEN) != 0) { if(_pn_append_to_path(pc->path, FS_DIR_SEP, FS_DIR_SEP_LEN, 0) == NULL) { strcpy(pc->errmsg, "Insufficient memory to record directory name"); return 1; }; }; };/* * Skip the separator unless we have reached the end of the path. */ if(*pptr==':') pptr++;/* * Return the unprocessed tail of the path-list string. */ *nextp = pptr; return 0;}/*....................................................................... * Read a username, stopping when a directory separator is seen, a colon * separator is seen, the end of the string is reached, or the username * buffer overflows. * * Input: * pc PathCache * The cache of filenames. * string char * The string who's prefix contains the name. * slen int The max number of characters to read from string[]. * literal int If true, treat backslashes as literal characters * instead of escapes. * Input/Output: * nextp char ** A pointer to the next unprocessed character * in string[] will be assigned to *nextp. * Output: * return int 0 - OK. The username can be found in pc->usrnam. * 1 - Error. A description of the error message * can be found in pc->errmsg. */static int pca_read_username(PathCache *pc, const char *string, int slen, int literal, const char **nextp){ int usrlen; /* The number of characters in pc->usrnam[] */ const char *sptr; /* A pointer into string[] */ int escaped = 0; /* True if the last character was a backslash *//* * Extract the username. */ for(sptr=string,usrlen=0; usrlen < USR_LEN && (sptr-string) < slen; sptr++) {/* * Stop if the end of the string is reached, or a directory separator * or un-escaped colon separator is seen. */ if(!*sptr || strncmp(sptr, FS_DIR_SEP, FS_DIR_SEP_LEN)==0 || (!escaped && *sptr == ':')) break;/* * Escape the next character? */ if(!literal && !escaped && *sptr == '\\') { escaped = 1; } else { escaped = 0; pc->usrnam[usrlen++] = *sptr; }; };/* * Did the username overflow the buffer? */ if(usrlen >= USR_LEN) { strcpy(pc->errmsg, "Username too long"); return 1; };/* * Terminate the string. */ pc->usrnam[usrlen] = '\0';/* * Indicate where processing of the input string should continue. */ *nextp = sptr; return 0;}/*....................................................................... * Create a new CacheMem object. * * Output: * return CacheMem * The new object, or NULL on error. */static CacheMem *new_CacheMem(void){ CacheMem *cm; /* The object to be returned *//* * Allocate the container. */ cm = (CacheMem *)malloc(sizeof(CacheMem)); if(!cm) { fprintf(stderr, "new_CacheMem: 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_CacheMem(). */ cm->sg = NULL; cm->files_dim = 0; cm->files = NULL; cm->nfiles = 0;/* * Allocate a list of string segments for storing filenames. */ cm->sg = _new_StringGroup(_pu_pathname_dim()); if(!cm->sg) return del_CacheMem(cm);/* * Allocate an array of pointers to filenames. * This will be extended later if needed. */ cm->files_dim = FILES_BLK_FACT; cm->files = (char **) malloc(sizeof(*cm->files) * cm->files_dim); if(!cm->files) { fprintf(stderr, "new_CacheMem: Insufficient memory to allocate array of files.\n"); return del_CacheMem(cm); }; return cm;}/*....................................................................... * Delete a CacheMem object. * * Input: * cm CacheMem * The object to be deleted. * Output: * return CacheMem * The deleted object (always NULL). */static CacheMem *del_CacheMem(CacheMem *cm){ if(cm) {/* * Delete the memory that was used to record filename strings. */ cm->sg = _del_StringGroup(cm->sg);/* * Delete the array of pointers to filenames. */ cm->files_dim = 0; if(cm->files) { free(cm->files); cm->files = NULL; };/* * Delete the container. */ free(cm); }; return NULL;}/*....................................................................... * Re-initialize the memory used to allocate filename strings. * * Input: * cm CacheMem * The memory cache to be cleared. */static void rst_CacheMem(CacheMem *cm){ _clr_StringGroup(cm->sg); cm->nfiles = 0; return;}/*....................................................................... * Append a new directory node to the list of directories read from the * path. * * Input: * pc PathCache * The filename cache. * dirname const char * The name of the new directory. * Output: * return int 0 - OK. * 1 - Error. */static int add_PathNode(PathCache *pc, const char *dirname){ PathNode *node; /* The new directory list node */ int relative; /* True if dirname[] is a relative pathname *//* * Have we been passed a relative pathname or an absolute pathname? */ relative = strncmp(dirname, FS_ROOT_DIR, FS_ROOT_DIR_LEN) != 0;/* * If it's an absolute pathname, ignore it if the corresponding * directory doesn't exist. */ if(!relative && !_pu_path_is_dir(dirname)) return 0;/* * Allocate a new list node to record the specifics of the new directory. */ node = (PathNode *) _new_FreeListNode(pc->node_mem); if(!node) { sprintf(pc->errmsg, "Insufficient memory to cache new directory."); return 1; };/* * Initialize the node. */ node->next = NULL; node->relative = relative; node->mem = relative ? pc->rel_mem : pc->abs_mem; node->dir = NULL; node->nfile = 0; node->files = NULL;/* * Make a copy of the directory pathname. */ node->dir = _sg_store_string(pc->abs_mem->sg, dirname, 0); if(!node->dir) { strcpy(pc->errmsg, "Insufficient memory to store directory name."); return 1; };/* * Scan absolute directories for files of interest, recording their names * in node->mem->sg and appending pointers to these names to the * node->mem->files[] array. */ if(!node->relative) { int nfile = node->nfile = pca_scan_dir(pc, node->dir, node->mem); if(nfile < 1) { /* No files matched or an error occurred */ node = (PathNode *) _del_FreeListNode(pc->node_mem, node); return nfile < 0; }; };/* * Append the new node to the list. */ if(pc->head) { pc->tail->next = node;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -