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

📄 cplfile.c

📁 xorp源码hg
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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);}

⌨️ 快捷键说明

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