?? expand.c
字號:
return 0; }; break; };/* * After passing the first character, turn off the explicit match * requirement. */ xplicit = 0; };/* * To get here the pattern must have been exhausted. If the filename * string matched, then the filename string must also have been * exhausted. */ return *fptr == '\0';}/*....................................................................... * Match a character range expression terminated by an unescaped close * square bracket. * * Input: * c int The character to be matched with the range * pattern. * pattern const char * The range pattern to be matched (ie. after the * initiating '[' character). * endp const char ** On output a pointer to the character following the * range expression will be assigned to *endp. * Output: * return int 0 - Doesn't match. * 1 - The character matched. */static int ef_matches_range(int c, const char *pattern, const char **endp){ const char *pptr = pattern; /* The pointer used to scan the pattern */ int invert = 0; /* True to invert the sense of the match */ int matched = 0; /* True if the character matched the pattern *//* * If the first character is a caret, the sense of the match is * inverted and only if the character isn't one of those in the * range, do we say that it matches. */ if(*pptr == '^') { pptr++; invert = 1; };/* * The hyphen is only a special character when it follows the first * character of the range (not including the caret). */ if(*pptr == '-') { pptr++; if(c == '-') { *endp = pptr; matched = 1; };/* * Skip other leading '-' characters since they make no sense. */ while(*pptr == '-') pptr++; };/* * The hyphen is only a special character when it follows the first * character of the range (not including the caret or a hyphen). */ if(*pptr == ']') { pptr++; if(c == ']') { *endp = pptr; matched = 1; }; };/* * Having dealt with the characters that have special meanings at * the beginning of a character range expression, see if the * character matches any of the remaining characters of the range, * up until a terminating ']' character is seen. */ while(!matched && *pptr && *pptr != ']') {/* * Is this a range of characters signaled by the two end characters * separated by a hyphen? */ if(*pptr == '-') { if(pptr[1] != ']') { if(c >= pptr[-1] && c <= pptr[1]) matched = 1; pptr += 2; };/* * A normal character to be compared directly. */ } else if(*pptr++ == c) { matched = 1; }; };/* * Find the terminating ']'. */ while(*pptr && *pptr != ']') pptr++;/* * Did we find a terminating ']'? */ if(*pptr == ']') { *endp = pptr + 1; return matched ? !invert : invert; };/* * If the pattern didn't end with a ']' then it doesn't match, regardless * of the value of the required sense of the match. */ *endp = pptr; return 0;}/*....................................................................... * This is a qsort() comparison function used to sort strings. * * Input: * v1, v2 void * Pointers to the two strings to be compared. * Output: * return int -1 -> v1 < v2. * 0 -> v1 == v2 * 1 -> v1 > v2 */static int ef_cmp_strings(const void *v1, const void *v2){ char * const *s1 = (char * const *) v1; char * const *s2 = (char * const *) v2; return strcmp(*s1, *s2);}/*....................................................................... * Preprocess a path, expanding ~/, ~user/ and $envvar references, using * ef->path as a work buffer, then copy the result into a cache entry, * and return a pointer to this copy. * * Input: * ef ExpandFile * The resource object of the file matcher. * pathlen int The length of the prefix of path[] to be expanded. * Output: * return char * A pointer to a copy of the output path in the * cache. On error NULL is returned, and a description * of the error is left in ef->errmsg[]. */static char *ef_expand_special(ExpandFile *ef, const char *path, int pathlen){ int spos; /* The index of the start of the path segment that needs */ /* to be copied from path[] to the output pathname. */ int ppos; /* The index of a character in path[] */ char *pptr; /* A pointer into the output path */ int escaped; /* True if the previous character was a '\' */ int i;/* * Clear the pathname buffer. */ _pn_clear_path(ef->path);/* * We need to perform two passes, one to expand environment variables * and a second to do tilde expansion. This caters for the case * where an initial dollar expansion yields a tilde expression. */ escaped = 0; for(spos=ppos=0; ppos < pathlen; ppos++) { int c = path[ppos]; if(escaped) { escaped = 0; } else if(c == '\\') { escaped = 1; } else if(c == '$') { int envlen; /* The length of the environment variable */ char *value; /* The value of the environment variable *//* * Record the preceding unrecorded part of the pathname. */ if(spos < ppos && _pn_append_to_path(ef->path, path + spos, ppos-spos, 0) == NULL) { strcpy(ef->errmsg, "Insufficient memory to expand path"); return NULL; };/* * Skip the dollar. */ ppos++;/* * Copy the environment variable name that follows the dollar into * ef->envnam[], stopping if a directory separator or end of string * is seen. */ for(envlen=0; envlen<ENV_LEN && ppos < pathlen && strncmp(path + ppos, FS_DIR_SEP, FS_DIR_SEP_LEN); envlen++) ef->envnam[envlen] = path[ppos++];/* * If the username overflowed the buffer, treat it as invalid (note that * on most unix systems only 8 characters are allowed in a username, * whereas our ENV_LEN is much bigger than that. */ if(envlen >= ENV_LEN) { strcpy(ef->errmsg, "Environment variable name too long"); return NULL; };/* * Terminate the environment variable name. */ ef->envnam[envlen] = '\0';/* * Lookup the value of the environment variable. */ value = getenv(ef->envnam); if(!value) { const char *fmt = "No expansion found for: $%.*s"; sprintf(ef->errmsg, fmt, ERRLEN - strlen(fmt), ef->envnam); return NULL; };/* * Copy the value of the environment variable into the output pathname. */ if(_pn_append_to_path(ef->path, value, -1, 0) == NULL) { strcpy(ef->errmsg, "Insufficient memory to expand path"); return NULL; };/* * Record the start of the uncopied tail of the input pathname. */ spos = ppos; }; };/* * Record the uncopied tail of the pathname. */ if(spos < ppos && _pn_append_to_path(ef->path, path + spos, ppos-spos, 0) == NULL) { strcpy(ef->errmsg, "Insufficient memory to expand path"); return NULL; };/* * If the first character of the resulting pathname is a tilde, * then attempt to substitute the home directory of the specified user. */ pptr = ef->path->name; if(*pptr == '~' && path[0] != '\\') { int usrlen; /* The length of the username following the tilde */ const char *homedir; /* The home directory of the user */ int homelen; /* The length of the home directory string */ int plen; /* The current length of the path */ int skip=0; /* The number of characters to skip after the ~user *//* * Get the current length of the output path. */ plen = strlen(ef->path->name);/* * Skip the tilde. */ pptr++;/* * Copy the optional username that follows the tilde into ef->usrnam[]. */ for(usrlen=0; usrlen<USR_LEN && *pptr && strncmp(pptr, FS_DIR_SEP, FS_DIR_SEP_LEN); usrlen++) ef->usrnam[usrlen] = *pptr++;/* * If the username overflowed the buffer, treat it as invalid (note that * on most unix systems only 8 characters are allowed in a username, * whereas our USR_LEN is much bigger than that. */ if(usrlen >= USR_LEN) { strcpy(ef->errmsg, "Username too long"); return NULL; };/* * Terminate the username string. */ ef->usrnam[usrlen] = '\0';/* * Lookup the home directory of the user. */ homedir = _hd_lookup_home_dir(ef->home, ef->usrnam); if(!homedir) { strncpy(ef->errmsg, _hd_last_home_dir_error(ef->home), ERRLEN); ef->errmsg[ERRLEN] = '\0'; return NULL; }; homelen = strlen(homedir);/* * ~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 must * erase it. */ if(strcmp(homedir, FS_ROOT_DIR) == 0 && strncmp(pptr, FS_DIR_SEP, FS_DIR_SEP_LEN) == 0) { skip = FS_DIR_SEP_LEN; };/* * If needed, increase the size of the pathname buffer to allow it * to accomodate the home directory instead of the tilde expression. * Note that pptr may not be valid after this call. */ if(_pn_resize_path(ef->path, plen - usrlen - 1 - skip + homelen)==NULL) { strcpy(ef->errmsg, "Insufficient memory to expand filename"); return NULL; };/* * Move the part of the pathname that follows the tilde expression to * the end of where the home directory will need to be inserted. */ memmove(ef->path->name + homelen, ef->path->name + 1 + usrlen + skip, plen - usrlen - 1 - skip+1);/* * Write the home directory at the beginning of the string. */ for(i=0; i<homelen; i++) ef->path->name[i] = homedir[i]; };/* * Copy the result into the cache, and return a pointer to the copy. */ return ef_cache_pathname(ef, ef->path->name, 0);}/*....................................................................... * Return a description of the last path-expansion error that occurred. * * Input: * ef ExpandFile * The path-expansion resource object. * Output: * return char * The description of the last error. */const char *ef_last_error(ExpandFile *ef){ return ef ? ef->errmsg : "NULL ExpandFile argument";}/*....................................................................... * Print out an array of matching files. * * Input: * result FileExpansion * The container of the sorted array of * expansions. * fp FILE * The output stream to write to. * term_width int The width of the terminal. * Output: * return int 0 - OK. * 1 - Error. */int ef_list_expansions(FileExpansion *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 expansions */ int row,col; /* The row and column being written to */ int i;/* * Check the arguments. */ if(!result || !fp) { fprintf(stderr, "ef_list_expansions: 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 filenames. */ maxlen = 0; for(i=0; i<result->nfile; i++) { int len = strlen(result->files[i]); 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->nfile + ncol - 1) / ncol;/* * Print the expansions 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->nfile) { const char *filename = result->files[m]; if(fprintf(fp, "%s%-*s%s", filename, (int) (ncol > 1 ? maxlen - strlen(filename):0), "", col<ncol-1 ? " " : "\r\n") < 0) return 1; } else { if(fprintf(fp, "\r\n") < 0) return 1; break; }; }; }; return 0;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -