diff options
| -rw-r--r-- | Makefile | 6 | ||||
| -rw-r--r-- | dynamic_array.c | 3 | ||||
| -rw-r--r-- | dynamic_array.h | 2 | ||||
| -rw-r--r-- | file_suggestions.c | 258 | ||||
| -rw-r--r-- | file_suggestions.h | 12 | ||||
| -rw-r--r-- | lexical_analysis.c | 28 | ||||
| -rw-r--r-- | lexical_analysis.h | 6 | ||||
| -rw-r--r-- | readline.c | 153 | ||||
| -rw-r--r-- | readline.h | 37 | ||||
| -rw-r--r-- | shell.c | 173 | ||||
| -rw-r--r-- | shell.h | 64 | 
11 files changed, 700 insertions, 42 deletions
| @@ -1,14 +1,14 @@ -SRCMODULES = dynamic_array.c queue.c lexical_analysis.c shell.c +SRCMODULES = dynamic_array.c queue.c lexical_analysis.c file_suggestions.c readline.c shell.c  OBJMODULES = $(SRCMODULES:.c=.o)  CC = gcc  CFLAGS = -Wall -g -c -all: shell-V +all: shell-edit  %.o: %.с %.h  	$(CC) $(CFLAGS) $< -o $@ -shell-V: $(OBJMODULES) +shell-edit: $(OBJMODULES)  	$(CC) $(LIBS) $^ -o $@  -include deps.mk diff --git a/dynamic_array.c b/dynamic_array.c index 5a24cb8..c0a8723 100644 --- a/dynamic_array.c +++ b/dynamic_array.c @@ -1,4 +1,5 @@  #include "dynamic_array.h" +  #include <stdlib.h>  void dynarr_create_array(struct dynamic_array *array) @@ -31,7 +32,7 @@ void dynarr_copy_array(struct dynamic_array *array, char *new_arr)          new_arr[i] = array->arr[i];  } -void dynarr_drop_word(struct dynamic_array *array) +void dynarr_reset_array(struct dynamic_array *array)  {      array->last_element_index = -1;  } diff --git a/dynamic_array.h b/dynamic_array.h index 98491ea..ae63fc4 100644 --- a/dynamic_array.h +++ b/dynamic_array.h @@ -14,7 +14,7 @@ struct dynamic_array {  void dynarr_create_array(struct dynamic_array *array);  void dynarr_push_back(struct dynamic_array *array, int letter);  void dynarr_copy_array(struct dynamic_array *array, char *new_arr); -void dynarr_drop_word(struct dynamic_array *array); +void dynarr_reset_array(struct dynamic_array *array);  void dynarr_clear(struct dynamic_array *array);  #endif diff --git a/file_suggestions.c b/file_suggestions.c new file mode 100644 index 0000000..528d717 --- /dev/null +++ b/file_suggestions.c @@ -0,0 +1,258 @@ +#include "file_suggestions.h" +#include "readline.h" + +#include <stdlib.h> +#include <sys/types.h> +#include <dirent.h> +#include <stdio.h> +#include <string.h> + +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; +} diff --git a/file_suggestions.h b/file_suggestions.h new file mode 100644 index 0000000..1b818a8 --- /dev/null +++ b/file_suggestions.h @@ -0,0 +1,12 @@ +#ifndef FILE_SUGGESTIONS_H_SENTRY +#define FILE_SUGGESTIONS_H_SENTRY + +#include "readline.h" + +int get_filename_match(struct readline_type *readline, int start_filename_idx); +int get_program_name_match(struct readline_type *readline); + +int get_start_filename_idx(struct readline_type *readline); +int suggestions_for_filename(struct readline_type *readline); + +#endif diff --git a/lexical_analysis.c b/lexical_analysis.c index 4349a69..5db57cb 100644 --- a/lexical_analysis.c +++ b/lexical_analysis.c @@ -123,11 +123,13 @@ int is_redirect_token(int ch, int next_ch)   */  int stream_redirect_tokens(struct w_queue *word_chain,                             struct dynamic_array *tmp_word, int ch, -                           struct param_type *params) +                           struct param_type *params, +                           struct readline_type *readline)  {      int next_ch; -    next_ch = getchar(); -    ungetc(next_ch, stdin); + +    if(ch == '>') +        next_ch = readline->arr[readline->considered_index + 1];      if(is_redirect_token(ch, next_ch)) {          add_word_or_filename(word_chain, tmp_word, params); @@ -138,7 +140,7 @@ int stream_redirect_tokens(struct w_queue *word_chain,          if(validate_redirections(ch, next_ch, params)) {              params->tokens = (ch == '>' && next_ch == '>') ? append : ch;              if(is_double_token(params)) -                getchar(); +                ++readline->considered_index;              return 1;          } else              params->wrong_command = err_redirect_stream_again; @@ -178,7 +180,7 @@ int pipeline_token_processing(struct w_queue *word_chain,      c_queue_push(cmdlines, cmdline);      w_queue_clear(word_chain); -    dynarr_drop_word(tmp_word); +    dynarr_reset_array(tmp_word);      return 1;  } @@ -187,11 +189,12 @@ int pipeline_token_processing(struct w_queue *word_chain,   */  int special_tokens(struct w_queue *word_chain, struct c_queue *cmdlines,                     struct dynamic_array *tmp_word, int ch, -                   struct param_type *params) +                   struct param_type *params, struct readline_type *readline)  { -    int next_ch; -    next_ch = getchar(); -    ungetc(next_ch, stdin); +    int next_ch, i; + +    if(ch == '|' || ch == '&') +        next_ch = readline->arr[readline->considered_index + 1];      if(is_special_token(ch, next_ch)) {          add_word_or_filename(word_chain, tmp_word, params); @@ -208,8 +211,9 @@ int special_tokens(struct w_queue *word_chain, struct c_queue *cmdlines,          } else if(ch == '&' && next_ch == '&')              params->tokens = and;          else if(ch == '&') { -            while((ch = getchar()) != new_line) { -                if(ch != whitespace && ch != tab) { +            for(i = readline->considered_index+1; readline->arr[i] != new_line; +                                                                        ++i) { +                if(readline->arr[i] != whitespace && readline->arr[i] != tab) {                      params->wrong_command = err_bg_process;                      return 0;                  } @@ -217,7 +221,7 @@ int special_tokens(struct w_queue *word_chain, struct c_queue *cmdlines,              params->tokens = '&';          }          if(is_double_token(params)) -                getchar(); +            ++readline->considered_index;          return 1;      }      return 0; diff --git a/lexical_analysis.h b/lexical_analysis.h index 3266ad7..9d7d556 100644 --- a/lexical_analysis.h +++ b/lexical_analysis.h @@ -2,6 +2,7 @@  #define LEXICAL_ANALYSIS_H_SENTRY  #include "shell.h" +#include "readline.h"  int is_double_quotes_pair(struct param_type params);  int escape_double_quotes_or_backslash(int ch, struct param_type params); @@ -26,7 +27,8 @@ int is_double_token(struct param_type *params);  int stream_redirect_tokens(struct w_queue *word_chain,                             struct dynamic_array *tmp_word, -                           int ch, struct param_type *params); +                           int ch, struct param_type *params, +                           struct readline_type *readline);  int double_quotes_again(int ch, struct param_type params); @@ -37,6 +39,6 @@ int pipeline_token_processing(struct w_queue *word_chain,  int special_tokens(struct w_queue *word_chain, struct c_queue *cmdlines,                     struct dynamic_array *tmp_word, int ch, -                   struct param_type *params); +                   struct param_type *params, struct readline_type *readline);  #endif diff --git a/readline.c b/readline.c new file mode 100644 index 0000000..c36b19a --- /dev/null +++ b/readline.c @@ -0,0 +1,153 @@ +#include "readline.h" +#include "shell.h" + +#include <stdlib.h> +#include <string.h> /* memmove */ +#include <stdio.h> + +void readline_create_array(struct readline_type *readline) +{ +    readline->arr = calloc(initial_size, 1); +    readline->cursor_pos = 0; +    readline->last_element_index = -1; +    readline->considered_index = 0; +    readline->allocation_size = initial_size; +} + +static void readline_copy_array(struct readline_type *readline, char *new_arr) +{ +    int i; +    for(i = 0; i <= readline->last_element_index; ++i) +        new_arr[i] = readline->arr[i]; +} + +static void readline_allocate_memory(struct readline_type *readline) +{ +    char *new_arr = calloc(readline->allocation_size * 2, 1); +    readline_copy_array(readline, new_arr); +    free(readline->arr); +    readline->arr = new_arr; +    readline->allocation_size *= 2; +} + +static void readline_reprint_modified_part(struct readline_type *readline, +                                           int begin_idx) +{ +    int i, counter; +    for(i = begin_idx, counter = 0; i <= readline->last_element_index; +                                                            ++i, ++counter) +        putchar(readline->arr[i]); + +    /* return cursor to previous position */ +    for( ; counter != 0; --counter) +        putchar('\b'); +    fflush(stdout); +} + +void readline_add_char(struct readline_type *readline, int ch) +{ +    char *begin_arr; +    int size; + +    if(readline->last_element_index+1 == readline->allocation_size) +        readline_allocate_memory(readline); +    /* insert in middle position */ +    if(readline->cursor_pos - 1 != readline->last_element_index) { +        begin_arr = readline->arr + readline->cursor_pos; +        size = readline->last_element_index - readline->cursor_pos + 1; +        memmove(begin_arr+1, begin_arr, size); +        readline->arr[readline->cursor_pos] = ch; +        ++readline->last_element_index; +        readline_reprint_modified_part(readline, readline->cursor_pos + 1); +    } else { +        ++readline->last_element_index; +        readline->arr[readline->last_element_index] = ch; +    } +    ++readline->cursor_pos; +} + +void readline_reset_array(struct readline_type *readline) +{ +    readline->last_element_index = -1; +    readline->cursor_pos = 0; +} + +void readline_clear(struct readline_type *readline) +{ +    free(readline->arr); +    readline->arr = NULL; +} + +void readline_print(struct readline_type *readline) +{ +    int i; +    for(i = 0; i <= readline->last_element_index; ++i) +        putchar(readline->arr[i]); +    readline->cursor_pos = readline->last_element_index + 1; +    fflush(stdout); +} + +enum keys readline_detect_arrow_keys(int ch) +{ +    char next_ch; +    if(ch == esc) { +        next_ch = getchar(); +        if(next_ch != '[') +            return unknown_key; +        next_ch = getchar(); + +        switch(next_ch) { +        case left_arrow: +            return left_arrow; +        case right_arrow: +            return right_arrow; +        case up_arrow: +            return up_arrow; +        case down_arrow: +            return down_arrow; +        default: +            return unknown_key; +        } +    } +    return none; +} + +void readline_move_along(struct readline_type *readline, enum keys found_key) +{ +    switch(found_key) { +    case left_arrow: +        if(readline->cursor_pos > 0) { +            putchar('\b'); +            fflush(stdout); +            --readline->cursor_pos; +        } +        break; +    case right_arrow: +        if(readline->cursor_pos <= readline->last_element_index) { +            putchar(readline->arr[readline->cursor_pos]); +            fflush(stdout); +            ++readline->cursor_pos; +        } +        break; +    default: +        ; +    } +} + +void readline_character_deletion(struct readline_type *readline) +{ +    char *begin_arr; +    int size; + +    if(readline->cursor_pos > 0) { +        putchar('\b'); +        fflush(stdout); +        begin_arr = readline->arr + readline->cursor_pos; +        size = readline->last_element_index - readline->cursor_pos + 1; +        memmove(begin_arr-1, begin_arr, size); +        readline->arr[readline->last_element_index] = ' '; +        readline_reprint_modified_part(readline, readline->cursor_pos - 1); +        --readline->last_element_index; +        --readline->cursor_pos; +    } +} diff --git a/readline.h b/readline.h new file mode 100644 index 0000000..b626cae --- /dev/null +++ b/readline.h @@ -0,0 +1,37 @@ +#ifndef READLINE_H_SENTRY +#define READLINE_H_SENTRY + +#include "readline.h" + +/* + * ends with these codes in escape sequence + * for the arrows + */ +enum keys{ +    left_arrow      = 'D', +    right_arrow     = 'C', +    up_arrow        = 'A', +    down_arrow      = 'B', +    none            =  0, +    unknown_key     =  -1, +    backspace       =  127 +}; + +struct readline_type { +    char *arr; +    int cursor_pos; +    int considered_index; +    int last_element_index; +    int allocation_size; +}; + +void readline_create_array(struct readline_type *readline); +void readline_add_char(struct readline_type *readline, int ch); +void readline_reset_array(struct readline_type *readline); +void readline_clear(struct readline_type *readline); +void readline_print(struct readline_type *readline_type); +enum keys readline_detect_arrow_keys(int ch); +void readline_move_along(struct readline_type *readline, enum keys found_key); +void readline_character_deletion(struct readline_type *readline); + +#endif @@ -2,6 +2,8 @@  #include "queue.h"  #include "dynamic_array.h"  #include "lexical_analysis.h" +#include "file_suggestions.h" +#include "readline.h"  #include <stdio.h>  #include <stdlib.h> @@ -11,6 +13,7 @@  #include <fcntl.h>  #include <signal.h>  #include <errno.h> +#include <termios.h>  MAKE_QUEUE_INIT(w_queue)  MAKE_QUEUE_INIT(p_queue) @@ -23,6 +26,7 @@ enum modes { word_separation, whole_word };  static void show_invitation()  {      printf("> "); +    fflush(stdout);  }  /* remove background zombie processes */ @@ -54,6 +58,7 @@ static void init_params(struct param_type *params, enum modes *current_mode)      /* 0 - success, 1 - error */      params->last_execution_status = 0;      params->pipeline = 0; +    params->new_readline = 1;      *current_mode = word_separation;  } @@ -74,11 +79,13 @@ static void reset_params(struct param_type *params,                           enum modes *current_mode,                           struct w_queue *word_chain,                           struct c_queue *cmdlines, -                         struct dynamic_array *tmp_word) +                         struct dynamic_array *tmp_word, +                         struct readline_type *readline)  {      w_queue_clear(word_chain);      c_queue_clear(cmdlines); -    dynarr_drop_word(tmp_word); +    dynarr_reset_array(tmp_word); +    readline_reset_array(readline);      clear_filename(params);      init_params(params, current_mode);  } @@ -126,11 +133,13 @@ void error_identification(const struct param_type *params)  static int special_token_handling(struct w_queue *word_chain,                                    struct c_queue *cmdlines,                                    struct dynamic_array *tmp_word, int ch, -                                  struct param_type *params) +                                  struct param_type *params, +                                  struct readline_type *readline)  {      return -        stream_redirect_tokens(word_chain, tmp_word, ch, params) ? -            1 : special_tokens(word_chain, cmdlines, tmp_word, ch, params); +        stream_redirect_tokens(word_chain, tmp_word, ch, params, readline) ? +            1 : special_tokens(word_chain, cmdlines, tmp_word, ch, params, +                               readline);  }  static void wait_for_process_to_complete(struct p_queue *pid_store) @@ -394,7 +403,7 @@ void add_filename(struct dynamic_array *tmp_word, struct param_type *params)              malloc(tmp_word->last_element_index+1);          dynarr_copy_array(tmp_word, params->streams.output_stream_to_append);      } -    dynarr_drop_word(tmp_word); +    dynarr_reset_array(tmp_word);      params->is_word = 0;  } @@ -405,7 +414,7 @@ void add_word(struct w_queue *word_chain, struct dynamic_array *tmp_word,      char *word = malloc(tmp_word->last_element_index+1);      dynarr_copy_array(tmp_word, word);      w_queue_push(word_chain, word); -    dynarr_drop_word(tmp_word); +    dynarr_reset_array(tmp_word);      params->is_word = 0;  } @@ -416,13 +425,86 @@ char** create_cmdline(const struct w_queue *word_chain, int word_counter)      return cmdline;  } +static int readline_termination_condition(int ch, +                                          struct readline_type *readline) +{ +    return +        ch == new_line || +            (ch == end_of_file && readline->last_element_index == -1); +} + +static void echo_characters(int ch) +{ +    write(1, &ch, 1); +} + +static void generate_readline(struct readline_type *readline) +{ +    enum keys found_key = none; +    int match_result; +    char ch; + +    while((ch = getchar()) && !readline_termination_condition(ch, readline)) { +        if(ch == tab) { +            if(suggestions_for_filename(readline)) { +                match_result = get_filename_match(readline, +                        get_start_filename_idx(readline)); +                if(!match_result) +                    echo_characters(new_line); +                show_invitation(); +                if(readline->last_element_index != -1) +                    readline_print(readline); +                /* program name is not empty */ +            } else if(readline->last_element_index != -1) { +                match_result = get_program_name_match(readline); +                if(!match_result) +                    echo_characters(new_line); +                show_invitation(); +                if(readline->last_element_index != -1) +                    readline_print(readline); +            } +            continue; +        } +        if(ch == end_of_file) +            continue; + +        /* moving */ +        found_key = readline_detect_arrow_keys(ch); +        if(found_key != none && found_key != unknown_key) { +            readline_move_along(readline, found_key); +            continue; +        } +        if(found_key == unknown_key) +            continue; + +        /* deletion */ +        if(ch == backspace) { +            readline_character_deletion(readline); +            continue; +        } + +        echo_characters(ch); +        readline_add_char(readline, ch); +    } +    /* moving cursor to end */ +    if(ch == new_line) +        readline->cursor_pos = readline->last_element_index + 1; +    /* adding '\n' to readline */ +    readline_add_char(readline, ch); +    /* print '\n' to end of readline */ +    if(ch == new_line) +        echo_characters(ch); +} +  static void command_processing(struct param_type *params, -                                enum modes *current_mode, -                                struct w_queue *word_chain, -                                struct c_queue *cmdlines, -                                struct dynamic_array *tmp_word, int ch) +                               enum modes *current_mode, +                               struct w_queue *word_chain, +                               struct c_queue *cmdlines, +                               struct dynamic_array *tmp_word, +                               struct readline_type *readline, int ch)  {      char **cmdline = NULL; +    int last_token = 0;      /* odd number of double quotes  */      if(!is_double_quotes_pair(*params)) { @@ -463,16 +545,22 @@ static void command_processing(struct param_type *params,  clean:      error_identification(params); -    if(params->tokens == '&' || params->tokens == 0 || ch == new_line) +    last_token = params->tokens; +    reset_params(params, current_mode, word_chain, cmdlines, tmp_word, +                 readline); + +    if(last_token == '&' || last_token == 0 || ch == new_line) {          show_invitation(); -    reset_params(params, current_mode, word_chain, cmdlines, tmp_word); +        generate_readline(readline); +    }  }  static void word_separation_processing(int ch, struct param_type *params,                                         enum modes *current_mode,                                         struct w_queue *word_chain,                                         struct c_queue *cmdlines, -                                       struct dynamic_array *tmp_word) +                                       struct dynamic_array *tmp_word, +                                       struct readline_type *readline)  {      /* could be a marker for the beginning of a blank word */      params->stored_symbol = ch; @@ -492,16 +580,18 @@ static void word_separation_processing(int ch, struct param_type *params,          params->escape_sequences = 1;          return;      } -    if(special_token_handling(word_chain, cmdlines, tmp_word, ch, params)) { +    if(special_token_handling(word_chain, cmdlines, tmp_word, ch, params, +                              readline)) {          if(command_execution_condition(params))              command_processing(params, current_mode, word_chain, cmdlines, -                               tmp_word, ch); +                               tmp_word, readline, ch);          return;      }      if(params->wrong_command) {          error_identification(params);          clean_input_buffer(); -        reset_params(params, current_mode, word_chain, cmdlines, tmp_word); +        reset_params(params, current_mode, word_chain, cmdlines, tmp_word, +                     readline);          show_invitation();          return;      } @@ -509,7 +599,8 @@ static void word_separation_processing(int ch, struct param_type *params,          if(excessive_words(ch, params)) {              error_identification(params);              clean_input_buffer(); -            reset_params(params, current_mode, word_chain, cmdlines, tmp_word); +            reset_params(params, current_mode, word_chain, cmdlines, tmp_word, +                         readline);              show_invitation();              return;          } @@ -560,33 +651,69 @@ static void whole_word_processing(int ch, struct param_type *params,      add_letter(ch, tmp_word, params);  } +static void change_terminal_settings(struct termios *cur_terminal_settings, +                                     struct termios *save_terminal_settings) +{ +    tcgetattr(0, save_terminal_settings); +    memcpy(cur_terminal_settings, save_terminal_settings, +           sizeof(*save_terminal_settings)); +    cur_terminal_settings->c_lflag &= ~(ICANON | ECHO); +    tcsetattr(0, TCSANOW, cur_terminal_settings); +} + +static void restore_terminal_settings(struct termios *cur_terminal_settings, +                                      struct termios *save_terminal_settings) +{ +    tcsetattr(0, TCSANOW, save_terminal_settings); +} +  int main()  { -    int ch; +    char ch; +    int i;      struct param_type params; +    struct termios cur_terminal_settings, save_terminal_settings;      struct w_queue word_chain;      struct c_queue cmdlines;      struct dynamic_array tmp_word; +    struct readline_type readline;      enum modes current_mode = word_separation; +    change_terminal_settings(&cur_terminal_settings, &save_terminal_settings);      w_queue_init(&word_chain);      c_queue_init(&cmdlines);      dynarr_create_array(&tmp_word); +    readline_create_array(&readline);      init_params(¶ms, ¤t_mode);      show_invitation(); +    generate_readline(&readline); + +    for(i = 0; readline.arr[i] != end_of_file; ) { +        ch = readline.arr[i]; +        readline.considered_index = i; + +        if(params.new_readline) +            params.new_readline = 0; -    while((ch = getchar()) != EOF) {          if(ch == new_line)              command_processing(¶ms, ¤t_mode, &word_chain, -                               &cmdlines, &tmp_word, ch); -        else if(current_mode == word_separation) +                               &cmdlines, &tmp_word, &readline, ch); +        else if(current_mode == word_separation) {              word_separation_processing(ch, ¶ms, ¤t_mode, &word_chain, -                                       &cmdlines, &tmp_word); +                                       &cmdlines, &tmp_word, &readline); +            /* double token was found */ +            if(readline.considered_index != i) +                ++i; +         }          else if(current_mode == whole_word)              whole_word_processing(ch, ¶ms, ¤t_mode, &word_chain,                                    &tmp_word); +        i = params.new_readline ? 0 : i + 1;      } + +    restore_terminal_settings(&cur_terminal_settings, &save_terminal_settings);      putchar(new_line);      dynarr_clear(&tmp_word); +    readline_clear(&readline);      return 0;  } @@ -0,0 +1,64 @@ +#ifndef SHELL_H_SENTRY +#define SHELL_H_SENTRY + +#include "dynamic_array.h" +#include "queue.h" + +enum { +    /* CTRL-D  */ +    end_of_file     = 4, +    new_line        = 10, +    whitespace      = ' ', +    tab             = 9, +    esc             = 27, +    backslash       = '\\', +    double_quotes   = '"' +}; + +/* two-letter tokens */ +enum { +    append          = '>' + 1, +    and             = '&' + 1, +    or              = '|' + 1 +}; + +/* error codes */ +enum { +    err_filename_expected           = 1, +    err_redirect_stream_again       = 2, +    err_redirect_stream_in_pipeline = 3, +    err_bg_process                  = 4, +    err_empty_command               = 5, +    err_extra_chars_after_filename  = 6, +    err_odd_double_quotes           = 7 +}; + +/* storing file names to redirect standard input/output streams */ +struct io_type { +    char *input_stream; +    char *output_stream; +    char *output_stream_to_append; +}; + +struct param_type { +    int is_word; +    int escape_sequences; +    unsigned int double_quotes_counter; +    char stored_symbol; +    int empty_word_flag; +    int tokens; +    int wrong_command; +    struct io_type streams; +    int last_execution_status; +    int pipeline; +    int new_readline; +}; + +int filename_waiting(struct param_type *params); +void add_filename(struct dynamic_array *tmp_word, struct param_type *params); +void add_word(struct w_queue *word_chain, struct dynamic_array *tmp_word, +              struct param_type *params); +int is_stream_redirection_set(const struct param_type *params); +char** create_cmdline(const struct w_queue *word_chain, int word_counter); + +#endif | 
