#include "file_suggestions.h" #include "readline.h" #include #include #include #include #include extern char **environ; static void clean_name_and_path(char *name, char *path) { if(name) free(name); if(strcmp(path, ".")) free(path); } static int print_all_filenames(const char *name, const char *path) { DIR *dir; struct dirent *dent; char *next_filename; int first_suggestion; first_suggestion = 1; dir = opendir(path); if(!dir) { perror(path); return 0; } while((dent = readdir(dir)) != NULL) { next_filename = dent->d_name; if(first_suggestion) { putchar('\n'); first_suggestion = 0; } printf("%s\n", next_filename); } closedir(dir); return 1; } static int matchmaking(const char *name, const char *path) { DIR *dir; struct dirent *dent; char *next_filename; int mismatch_status, first_suggestion, something_found; mismatch_status = 0; something_found = 0; first_suggestion = 1; dir = opendir(path); if(!dir) { perror(path); return 0; } while((dent = readdir(dir)) != NULL) { next_filename = dent->d_name; int i; for(i = 0; name[i] && next_filename[i]; ++i) { if(name[i] != next_filename[i]) { mismatch_status = 1; break; } } if(!mismatch_status && name[i] == '\0') { if(first_suggestion) { putchar('\n'); first_suggestion = 0; } printf("%s\n", next_filename); if(!something_found) something_found = 1; } mismatch_status = 0; } closedir(dir); return something_found; } static void extract_path_and_name(char **path, char **name, struct readline_type *readline, int start_filename_idx) { int i, j, k; for(i = readline->last_element_index; i >= start_filename_idx; --i) { if(readline->arr[i] == '/') break; } *path = malloc(i - start_filename_idx+ 2); *name = malloc(readline->last_element_index - i + 1); /* extract path */ for(j = start_filename_idx, k = 0; j <= i; ++j, ++k) (*path)[k] = readline->arr[j]; (*path)[k] = '\0'; /* extract name */ for(j = i + 1, k = 0; j <= readline->last_element_index; ++j, ++k) (*name)[k] = readline->arr[j]; (*name)[k] = '\0'; } static void copy_filename(char *dest, char *source, int start_idx, int last_idx) { int i, j; for(i = 0, j = start_idx; j <= last_idx; ++i, ++j) dest[i] = source[j]; } static void extract_only_filename(char **name, struct readline_type *readline, int start_filename_idx) { int size = readline->last_element_index - start_filename_idx + 2; *name = malloc(size); copy_filename(*name, readline->arr, start_filename_idx, readline->last_element_index); (*name)[size-1] = '\0'; } int get_filename_match(struct readline_type *readline, int start_filename_idx) { int extract_path_status, match_result; char *name = NULL; extract_path_status = 0; match_result = 0; /* default path */ char *path = "."; int i; for(i = start_filename_idx; i <= readline->last_element_index; ++i) { if(readline->arr[i] == '/') { extract_path_status = 1; break; } } /* not empty filename */ if(readline->arr[start_filename_idx] != ' ') extract_path_status ? extract_path_and_name(&path, &name, readline, start_filename_idx) : extract_only_filename(&name, readline, start_filename_idx); match_result = (name == NULL && !strcmp(path, ".")) ? print_all_filenames(name, path) : matchmaking(name, path); clean_name_and_path(name, path); return match_result; } static int is_token(int ch) { return ch == ' ' || ch == '|' || ch == '&' || ch == ';' || ch == '<' || ch == '>'; } int get_start_filename_idx(struct readline_type *readline) { /* empty filename */ if(readline->last_element_index == ' ') return readline->last_element_index; int i; for(i = readline->last_element_index; i != -1; --i) { if(is_token(readline->arr[i])) return ++i; } return 0; } /* * 1 searching for suggestions for file name, * 0 searching for program name from PATH */ int suggestions_for_filename(struct readline_type *readline) { int token_status, i; token_status = 0; for(i = readline->last_element_index; i != -1; --i) { if(is_token(readline->arr[i])) { token_status = 1; continue; } if(token_status && !is_token(readline->arr[i])) return 1; } return 0; } int find_separator_index(char *path, int begin_idx) { int i; for(i = begin_idx; path[i] != ':' && path[i]; ++i) {} return i; } int get_program_name_match(struct readline_type *readline) { char *name = NULL; char *path = NULL; char *path_variable = NULL; int size, begin_idx, end_idx, result; begin_idx = 0; end_idx = 0; result = 0; size = readline->last_element_index + 2; name = malloc(size); /* extracting prog name */ int i; for(i = 0; i <= readline->last_element_index; ++i) name[i] = readline->arr[i]; name[i] = '\0'; /* searching PATH */ for(i = 0; environ[i]; ++i) if(!strncmp(environ[i], "PATH", 4)) { path_variable = environ[i]; break; } if(!path_variable) return 0; /* skipping PATH= */ path_variable = path_variable + 5; /* directory search by separator (:) */ end_idx = find_separator_index(path_variable, begin_idx); size = end_idx + 1; path = malloc(size); copy_filename(path, path_variable, begin_idx, end_idx - 1); path[end_idx] = '\0'; result = matchmaking(name, path) ? 1 : result; free(path); /* if end_idx is beginning with ':' */ while(path_variable[end_idx]) { begin_idx = end_idx + 1; end_idx = find_separator_index(path_variable, begin_idx); size = end_idx + 1; path = malloc(size); copy_filename(path, path_variable, begin_idx, end_idx - 1); path[end_idx] = '\0'; result = matchmaking(name, path) ? 1 : result; free(path); } free(name); return result; }