diff options
| author | scratko <m@scratko.xyz> | 2024-06-14 15:15:41 +0300 | 
|---|---|---|
| committer | scratko <m@scratko.xyz> | 2024-06-14 15:25:55 +0300 | 
| commit | 8f4f87eabec13330a2b3a974975053c1e4632a11 (patch) | |
| tree | 58b0eae595fd62063287ca8fc727127166469e65 | |
| parent | 1ee0911f2def54f1b63d18b0924ac65c2db92f11 (diff) | |
| download | shell-8f4f87eabec13330a2b3a974975053c1e4632a11.tar.gz shell-8f4f87eabec13330a2b3a974975053c1e4632a11.tar.bz2 shell-8f4f87eabec13330a2b3a974975053c1e4632a11.zip | |
Shell-V release
Added pipeline.
Formatting shell.c (created lexical_analysys.c).
Error codes.
Some functions of queue.c are created by preprocessor.
| -rw-r--r-- | lexical_analysis.c | 50 | ||||
| -rw-r--r-- | lexical_analysis.h | 56 | ||||
| -rw-r--r-- | queue.c | 58 | ||||
| -rw-r--r-- | queue.h | 3 | ||||
| -rw-r--r-- | shell.c | 553 | 
5 files changed, 192 insertions, 528 deletions
| diff --git a/lexical_analysis.c b/lexical_analysis.c index f931118..4349a69 100644 --- a/lexical_analysis.c +++ b/lexical_analysis.c @@ -1,5 +1,6 @@  #include "lexical_analysis.h" -MAKE_QUEUE_PUSH(c_queue, cmdline, char**) + +#include <stdio.h>  int is_double_quotes_pair(struct param_type params)  { @@ -48,18 +49,14 @@ int is_empty_word(int ch, struct param_type params)  int command_execution_condition(struct param_type *params)  {      return -        (!filename_waiting(params) && !params->pipeline) || +        (params->tokens != '<' && params->tokens != '>' && +                params->tokens != append && !params->pipeline) ||          (params->pipeline && params->tokens == '&');  } -int is_special_token(int ch) +int is_first_special_token_character(int ch)  { -    return ch == and || ch == or || ch == '&' || ch == ';' || ch == '|'; -} - -int is_redirect_token(int ch, int next_ch) -{ -    return ch == '<' || ch == '>' || (ch == '>' && next_ch == '>'); +    return ch == '<' || ch == '>' || ch == '&' || ch == '|' || ch == ';';  }  int excessive_words(int ch, struct param_type *params) @@ -72,8 +69,10 @@ int excessive_words(int ch, struct param_type *params)          while((next_ch = getchar()) != new_line) {              if(next_ch == ' ')                  continue; -            if(!is_special_token(next_ch) && next_ch != '<' && next_ch != '>') +            if(!is_first_special_token_character(next_ch)) { +                params->wrong_command = err_extra_chars_after_filename;                  return 1; +            }              else                  break;          } @@ -88,7 +87,7 @@ void add_word_or_filename(struct w_queue *word_chain,  {      /* filenames */      if(filename_waiting(params) && !params->wrong_command) -            add_filename(tmp_word, params); +        add_filename(tmp_word, params);      /* execute command */      else if(params->is_word)          add_word(word_chain, tmp_word, params); @@ -108,6 +107,17 @@ int is_double_token(struct param_type *params)              params->tokens == append;  } +int is_special_token(int ch, int next_ch) +{ +    return (ch == '&' && next_ch == '&') || (ch == '|' && ch == '|') || +            ch == '&' || ch == ';' || ch == '|'; +} + +int is_redirect_token(int ch, int next_ch) +{ +    return ch == '<' || ch == '>' || (ch == '>' && next_ch == '>'); +} +  /*   * redirection token verification   */ @@ -130,14 +140,16 @@ int stream_redirect_tokens(struct w_queue *word_chain,              if(is_double_token(params))                  getchar();              return 1; -        } else { -            fprintf(stderr, "syntax error\n"); -            params->wrong_command = 1; -        } +        } else +            params->wrong_command = err_redirect_stream_again;      }      return 0;  } +/* + * the first element of the pipeline outputs to a file or + * redirects to a file in the middle of the pipeline + */  int wrong_streams_redirection(struct param_type *params)  {      return @@ -156,8 +168,7 @@ int pipeline_token_processing(struct w_queue *word_chain,      char **cmdline = NULL;      if(is_stream_redirection_set(params) &&              wrong_streams_redirection(params)) { -        /* TODO: add error codes */ -        params->wrong_command = 1; +        params->wrong_command = err_redirect_stream_in_pipeline;          return 0;      }      params->tokens = '|'; @@ -182,7 +193,7 @@ int special_tokens(struct w_queue *word_chain, struct c_queue *cmdlines,      next_ch = getchar();      ungetc(next_ch, stdin); -    if(is_special_token(ch)) { +    if(is_special_token(ch, next_ch)) {          add_word_or_filename(word_chain, tmp_word, params);          if(params->wrong_command) @@ -199,8 +210,7 @@ int special_tokens(struct w_queue *word_chain, struct c_queue *cmdlines,          else if(ch == '&') {              while((ch = getchar()) != new_line) {                  if(ch != whitespace && ch != tab) { -                    fprintf(stderr, "incorrect command\n"); -                    params->wrong_command = 1; +                    params->wrong_command = err_bg_process;                      return 0;                  }              } diff --git a/lexical_analysis.h b/lexical_analysis.h index e0f791a..3266ad7 100644 --- a/lexical_analysis.h +++ b/lexical_analysis.h @@ -1,54 +1,7 @@  #ifndef LEXICAL_ANALYSIS_H_SENTRY  #define LEXICAL_ANALYSIS_H_SENTRY -#include "queue.h" -#include "dynamic_array.h" - -#include <stdio.h> -#include <stdlib.h> - -enum { -    new_line        = 10, -    whitespace      = ' ', -    tab             = 9, -    backslash       = '\\', -    double_quotes   = '"' -}; - -/* two-letter tokens */ -enum { -    append          = '>' + 1, -    and             = '&' + 1, -    or              = '|' + 1 -}; - -/* 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 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); +#include "shell.h"  int is_double_quotes_pair(struct param_type params);  int escape_double_quotes_or_backslash(int ch, struct param_type params); @@ -60,19 +13,23 @@ int start_escape_sequence(int ch, struct param_type params);  int is_empty_word(int ch, struct param_type params);  int command_execution_condition(struct param_type *params); -int is_special_token(int ch); +int is_special_token(int ch, int next_ch);  int is_redirect_token(int ch, int next_ch);  int excessive_words(int ch, struct param_type *params); +  void add_word_or_filename(struct w_queue *word_chain,                            struct dynamic_array *tmp_word,                            struct param_type *params); +  int validate_redirections(int ch, int next_ch, struct param_type *params);  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 double_quotes_again(int ch, struct param_type params); +  int pipeline_token_processing(struct w_queue *word_chain,                                struct c_queue *cmdlines,                                struct dynamic_array *tmp_word, @@ -81,4 +38,5 @@ 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); +  #endif @@ -1,27 +1,6 @@  #include "queue.h"  #include <stdlib.h> -#if 0 -void w_queue_init(struct w_queue *q) -{ -    q->first = NULL; -    q->last = NULL; -} - -void w_queue_push(struct w_queue *q, char *word) -{ -    struct word_item *tmp = malloc(sizeof(struct word_item)); -    tmp->word = word; -    tmp->next = NULL; -    if(!q->first) { -        q->first = tmp; -        q->last = q->first; -    } else { -        q->last->next = tmp; -        q->last = q->last->next; -    } -} -#endif  void w_queue_clear(struct w_queue *q)  {      struct word_item *tmp; @@ -58,22 +37,6 @@ void c_queue_init(struct c_queue *q)      q->last_extracted_item = NULL;  } -#if 0 -void c_queue_push(struct c_queue *q, char **cmdline) -{ -    struct cmdline_item *tmp = malloc(sizeof(struct cmdline_item)); -    tmp->cmdline = cmdline; -    tmp->next = NULL; -    if(!q->first) { -        q->first = tmp; -        q->last = q->first; -    } else { -        q->last->next = tmp; -        q->last = q->last->next; -    } -} -#endif -  int c_queue_is_empty(struct c_queue *q)  {      return q->last_extracted_item->next == NULL; @@ -111,27 +74,6 @@ void c_queue_clear(struct c_queue *q)      q->last = NULL;      q->last_extracted_item = NULL;  } -#if 0 -void p_queue_init(struct p_queue *q) -{ -    q->first = NULL; -    q->last = NULL; -} - -void p_queue_push(struct p_queue *q, int pid) -{ -    struct pid_item *tmp = malloc(sizeof(struct pid_item)); -    tmp->pid = pid; -    tmp->next = NULL; -    if(!q->first) { -        q->first = tmp; -        q->last = q->first; -    } else { -        q->last->next = tmp; -        q->last = q->last->next; -    } -} -#endif  int p_queue_find_pid(struct p_queue *q, int pid)  { @@ -59,7 +59,10 @@ int w_queue_get_word_count(const struct w_queue *q);  void w_queue_copy_words_to_args(const struct w_queue *q, char **cmdline);  void c_queue_init(struct c_queue *q); + +/* used in shell.c and lexical_analysis.c */  void c_queue_push(struct c_queue *q, char **cmdline); +  char** c_queue_pop(struct c_queue *q);  void c_queue_clear(struct c_queue *q);  int c_queue_is_empty(struct c_queue *q); @@ -1,3 +1,4 @@ +#include "shell.h"  #include "queue.h"  #include "dynamic_array.h"  #include "lexical_analysis.h" @@ -14,56 +15,16 @@  MAKE_QUEUE_INIT(w_queue)  MAKE_QUEUE_INIT(p_queue)  MAKE_QUEUE_PUSH(w_queue, word, char*) +MAKE_QUEUE_PUSH(c_queue, cmdline, char**)  MAKE_QUEUE_PUSH(p_queue, pid, int)  enum modes { word_separation, whole_word }; -#if 0 -enum { -    new_line        = 10, -    whitespace      = ' ', -    tab             = 9, -    backslash       = '\\', -    double_quotes   = '"' -}; - -/* two-letter tokens */ -enum { -    append          = '>' + 1, -    and             = '&' + 1, -    or              = '|' + 1 -}; - -/* 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; -}; -#endif  static void show_invitation()  {      printf("> ");  } -static void print_error() -{ -    fprintf(stderr, "Error: unmatched quotes\n"); -} -  /* remove background zombie processes */  static void handler(int signal)  { @@ -121,59 +82,6 @@ static void reset_params(struct param_type *params,      clear_filename(params);      init_params(params, current_mode);  } -#if 0 -static int is_double_quotes_pair(struct param_type params) -{ -    return !(params.double_quotes_counter % 2); -} -static int check_separation(int ch, struct param_type params) -{ -    return (ch == whitespace || ch == tab) && params.is_word && -            !params.escape_sequences; -} -#endif -int filename_waiting(struct param_type *params) -{ -    if(params->tokens == '<' || params->tokens == '>' || -            params->tokens == append) { -        if(!params->is_word) -            params->wrong_command = 1; -        return 1; -    } else -        return 0; -} - -void add_filename(struct dynamic_array *tmp_word, struct param_type *params) -{ -    dynarr_push_back(tmp_word, '\0'); -    switch(params->tokens) { -    case '<': -        params->streams.input_stream = malloc(tmp_word->last_element_index+1); -        dynarr_copy_array(tmp_word, params->streams.input_stream); -        break; -    case '>': -        params->streams.output_stream = malloc(tmp_word->last_element_index+1); -        dynarr_copy_array(tmp_word, params->streams.output_stream); -        break; -    case append: -        params->streams.output_stream_to_append = -            malloc(tmp_word->last_element_index+1); -        dynarr_copy_array(tmp_word, params->streams.output_stream_to_append); -    } -    dynarr_drop_word(tmp_word); -    params->is_word = 0; -} - -void add_word(struct w_queue *word_chain, struct dynamic_array *tmp_word, -              struct param_type *params) -{ -    dynarr_push_back(tmp_word, 0); -    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); -    params->is_word = 0; -}  static void add_letter(int ch, struct dynamic_array *tmp_word,                         struct param_type *params) @@ -183,161 +91,37 @@ static void add_letter(int ch, struct dynamic_array *tmp_word,      params->escape_sequences = 0;  } -#if 0 -static int is_double_token(struct param_type *params) -{ -    return params->tokens == and || params->tokens == or || -            params->tokens == append; -} -static int is_redirect_token(int ch, int next_ch) -{ -    return ch == '<' || ch == '>' || (ch == '>' && next_ch == '>'); -} -static int validate_redirections(int ch, int next_ch, struct param_type *params) -{ -    return (ch == '<' && params->streams.input_stream == NULL) || -            ((ch == '>' || (ch == '>' && next_ch == '>')) && -             params->streams.output_stream == NULL && -             params->streams.output_stream_to_append == NULL); -} -static void add_word_or_filename(struct w_queue *word_chain, -                                 struct dynamic_array *tmp_word, -                                 struct param_type *params) -{ -    /* filenames */ -    if(filename_waiting(params) && !params->wrong_command) -            add_filename(tmp_word, params); -    /* execute command */ -    else if(params->is_word) -        add_word(word_chain, tmp_word, params); -} - -static int stream_redirect_tokens(struct w_queue *word_chain, -                                  struct dynamic_array *tmp_word, int ch, -                                  struct param_type *params) -{ -    int next_ch; -    next_ch = getchar(); -    ungetc(next_ch, stdin); - -    if(is_redirect_token(ch, next_ch)) { -        add_word_or_filename(word_chain, tmp_word, params); - -        if(params->wrong_command) -            return 0; - -        if(validate_redirections(ch, next_ch, params)) { -            params->tokens = (ch == '>' && next_ch == '>') ? append : ch; -            if(is_double_token(params)) -                getchar(); -            return 1; -        } else { -            fprintf(stderr, "syntax error\n"); -            params->wrong_command = 1; -        } -    } -    return 0; -} -#endif -  static void clean_input_buffer()  {      int ch;      while((ch = getchar()) != new_line)      {}  } -#if 0 -static int is_special_token(int ch) -{ -    return ch == and || ch == or || ch == '&' || ch == ';' || ch == '|'; -} -static int wrong_streams_redirection(struct param_type *params) -{ -    return -        (!params->pipeline && (params->tokens == '>' || -                               params->tokens == append)) || -        (params->pipeline && (params->tokens == '>' || -                              params->tokens == append || -                              params->tokens == '<')); -} -#endif -char** create_cmdline(const struct w_queue *word_chain, int word_counter) +static void print_error_msg(const char *error_msg)  { -    char **cmdline = malloc((word_counter + 1) * sizeof(char*)); -    w_queue_copy_words_to_args(word_chain, cmdline); -    return cmdline; +    if(error_msg) +        fprintf(stderr, "%s\n", error_msg);  } -int is_stream_redirection_set(const struct param_type *params) -{ -    return params->streams.input_stream || params->streams.output_stream || -            params->streams.output_stream_to_append; -} -#if 0 -static int pipeline_token_processing(struct w_queue *word_chain, -                                     struct c_queue *cmdlines, -                                     struct dynamic_array *tmp_word, -                                     struct param_type *params) +static const char* error_code_to_token(int error_code)  { -    char **cmdline = NULL; -    if(is_stream_redirection_set(params) && -            wrong_streams_redirection(params)) { -        /* TODO: add error codes */ -        params->wrong_command = 1; -        return 0; +    switch(error_code) { +    case err_filename_expected:             return "expected file name"; +    case err_redirect_stream_again:         return "stream redirected again"; +    case err_redirect_stream_in_pipeline:   return "bad stream redirect in pipe"; +    case err_bg_process:                    return "extra characters after &"; +    case err_empty_command:                 return "empty command"; +    case err_extra_chars_after_filename:    return "extra chars after filename"; +    case err_odd_double_quotes:             return "odd number of double quotes";      } -    params->tokens = '|'; -    params->pipeline = 1; -    cmdline = -        create_cmdline(word_chain, w_queue_get_word_count(word_chain)); - -    c_queue_push(cmdlines, cmdline); -    w_queue_clear(word_chain); -    dynarr_drop_word(tmp_word); -    return 1; +    return NULL;  } -static int special_tokens(struct w_queue *word_chain, -                          struct c_queue *cmdlines, -                          struct dynamic_array *tmp_word, int ch, -                          struct param_type *params) +void error_identification(const struct param_type *params)  { -    int next_ch; -    next_ch = getchar(); -    ungetc(next_ch, stdin); - -    if(is_special_token(ch)) { -        add_word_or_filename(word_chain, tmp_word, params); - -        if(params->wrong_command) -            return 0; - -        if(ch == '|' && next_ch == '|') -            params->tokens = or; -        else if(ch == '|') { -            if(!pipeline_token_processing(word_chain, cmdlines, tmp_word, -                                          params)) -                return 0; -        } else if(ch == '&' && next_ch == '&') -            params->tokens = and; -        else if(ch == '&') { -            while((ch = getchar()) != new_line) { -                if(ch != whitespace && ch != tab) { -                    fprintf(stderr, "incorrect command\n"); -                    params->wrong_command = 1; -                    return 0; -                } -            } -            params->tokens = '&'; -        } -        if(is_double_token(params)) -                getchar(); -        return 1; -    } -    return 0; +    print_error_msg(error_code_to_token(params->wrong_command));  } -#endif  static int special_token_handling(struct w_queue *word_chain,                                    struct c_queue *cmdlines, @@ -348,113 +132,6 @@ static int special_token_handling(struct w_queue *word_chain,          stream_redirect_tokens(word_chain, tmp_word, ch, params) ?              1 : special_tokens(word_chain, cmdlines, tmp_word, ch, params);  } -#if 0 -static int ignore_spaces(int ch, struct param_type params) -{ -    return (ch == whitespace || ch == tab) && !params.escape_sequences; -} - -static int change_mode(int ch, struct param_type params) -{ -    return ch == '"' && !params.escape_sequences; -} - -static int start_escape_sequence(int ch, struct param_type params) -{ -    return ch == backslash && !params.escape_sequences; -} - -/* name of file for opening stream already exists */ - -static int excessive_words(int ch, const struct param_type *params) -{ -    int next_ch; - -    if(filename_waiting(params)) { -        if(ch == new_line) -            return 0; -        while((next_ch = getchar()) != new_line) { -            if(next_ch == ' ') -                continue; -            if(!is_special_token(next_ch) && next_ch != '<' && next_ch != '>') -                return 1; -            else -                break; -        } -        ungetc(next_ch, stdin); -    } -    return 0; -} -#endif - -static int is_cd_command(const char *arg) -{ -    return !strcmp(arg, "cd"); -} - -static void change_directory(char **cmdline) -{ -    int result; -    char *first_arg = cmdline[1]; -    char *path = NULL; -    /* change to user home directory */ -    if(first_arg == NULL) { -        path = getenv("HOME"); -        if(!path) { -            perror("I don't know where's your home..."); -            return; -        } -    } else { -        if(cmdline[2]) { -            perror("cd: too many arguments"); -            return; -        } -        path = first_arg; -    } -    result = chdir(path); -    if(result == -1) -        perror(path); -} - -static void open_files(const struct param_type *params, int *input_fd, -                      int *output_fd) -{ -    if(params->streams.input_stream) -        *input_fd = open(params->streams.input_stream, O_RDONLY); -    if(params->streams.output_stream) -        *output_fd = open(params->streams.output_stream, O_WRONLY | O_CREAT | -                          O_TRUNC, 0666); -    if(params->streams.output_stream_to_append) -        *output_fd = open(params->streams.output_stream_to_append, O_WRONLY | -                          O_APPEND, 0666); -} - -static void change_streams(int input_fd, int output_fd, int is_pipeline, -                           int is_begin_pipeline) -{ -    if((!is_pipeline && input_fd) || -            (is_pipeline && is_begin_pipeline && input_fd)) { -        dup2(input_fd, 0); -        close(input_fd); -    } -    if((!is_pipeline && output_fd) || -            (is_pipeline && !is_begin_pipeline && output_fd)) { -        dup2(output_fd, 1); -        close(output_fd); -    } -} - -static void set_signal_disposition(struct param_type *params) -{ -    if(params->tokens == '&') -        /* zombie process termination on signal */ -        signal(SIGCHLD, handler); -    else -        /* the parent process will wait for the process to complete; -           default signal disposition -         */ -        signal(SIGCHLD, SIG_DFL); -}  static void wait_for_process_to_complete(struct p_queue *pid_store)  { @@ -499,6 +176,39 @@ static void postprocessing(struct w_queue *word_chain, struct c_queue *cmdlines,      p_queue_clear(pid_store);  } +static void set_signal_disposition(struct param_type *params) +{ +    if(params->tokens == '&') +        /* zombie process termination on signal */ +        signal(SIGCHLD, handler); +    else +        /* the parent process will wait for the process to complete; +           default signal disposition +         */ +        signal(SIGCHLD, SIG_DFL); +} + +static void change_streams(int input_fd, int output_fd, int is_pipeline, +                           int is_begin_pipeline) +{ +    if((!is_pipeline && input_fd) || +            (is_pipeline && is_begin_pipeline && input_fd)) { +        dup2(input_fd, 0); +        close(input_fd); +    } +    if((!is_pipeline && output_fd) || +            (is_pipeline && !is_begin_pipeline && output_fd)) { +        dup2(output_fd, 1); +        close(output_fd); +    } +} + +int is_stream_redirection_set(const struct param_type *params) +{ +    return params->streams.input_stream || params->streams.output_stream || +            params->streams.output_stream_to_append; +} +  static void make_pipeline(struct w_queue *word_chain, struct c_queue *cmdlines,                            struct param_type *params,                            int input_fd, int output_fd) @@ -540,6 +250,7 @@ static void make_pipeline(struct w_queue *word_chain, struct c_queue *cmdlines,              if(!c_queue_is_empty(cmdlines)) {                  dup2(save_read_fd, 0);                  close(save_read_fd); +                close(fd[0]);                  dup2(fd[1], 1);                  close(fd[1]);              } else { @@ -565,6 +276,48 @@ static void make_pipeline(struct w_queue *word_chain, struct c_queue *cmdlines,                     output_fd);  } +static void open_files(const struct param_type *params, int *input_fd, +                      int *output_fd) +{ +    if(params->streams.input_stream) +        *input_fd = open(params->streams.input_stream, O_RDONLY); +    if(params->streams.output_stream) +        *output_fd = open(params->streams.output_stream, O_WRONLY | O_CREAT | +                          O_TRUNC, 0666); +    if(params->streams.output_stream_to_append) +        *output_fd = open(params->streams.output_stream_to_append, O_WRONLY | +                          O_APPEND, 0666); +} + +static int is_cd_command(const char *arg) +{ +    return !strcmp(arg, "cd"); +} + +static void change_directory(char **cmdline) +{ +    int result; +    char *first_arg = cmdline[1]; +    char *path = NULL; +    /* change to user home directory */ +    if(first_arg == NULL) { +        path = getenv("HOME"); +        if(!path) { +            perror("I don't know where's your home..."); +            return; +        } +    } else { +        if(cmdline[2]) { +            perror("cd: too many arguments"); +            return; +        } +        path = first_arg; +    } +    result = chdir(path); +    if(result == -1) +        perror(path); +} +  static void run_external_program(struct w_queue *word_chain,                                   struct c_queue *cmdlines,                                   struct param_type *params) @@ -613,6 +366,56 @@ static void run_external_program(struct w_queue *word_chain,      }  } +int filename_waiting(struct param_type *params) +{ +    if(params->tokens == '<' || params->tokens == '>' || +            params->tokens == append) { +        if(!params->is_word) +            params->wrong_command = err_filename_expected; +        return 1; +    } else +        return 0; +} + +void add_filename(struct dynamic_array *tmp_word, struct param_type *params) +{ +    dynarr_push_back(tmp_word, '\0'); +    switch(params->tokens) { +    case '<': +        params->streams.input_stream = malloc(tmp_word->last_element_index+1); +        dynarr_copy_array(tmp_word, params->streams.input_stream); +        break; +    case '>': +        params->streams.output_stream = malloc(tmp_word->last_element_index+1); +        dynarr_copy_array(tmp_word, params->streams.output_stream); +        break; +    case append: +        params->streams.output_stream_to_append = +            malloc(tmp_word->last_element_index+1); +        dynarr_copy_array(tmp_word, params->streams.output_stream_to_append); +    } +    dynarr_drop_word(tmp_word); +    params->is_word = 0; +} + +void add_word(struct w_queue *word_chain, struct dynamic_array *tmp_word, +              struct param_type *params) +{ +    dynarr_push_back(tmp_word, 0); +    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); +    params->is_word = 0; +} + +char** create_cmdline(const struct w_queue *word_chain, int word_counter) +{ +    char **cmdline = malloc((word_counter + 1) * sizeof(char*)); +    w_queue_copy_words_to_args(word_chain, cmdline); +    return cmdline; +} +  static void command_processing(struct param_type *params,                                  enum modes *current_mode,                                  struct w_queue *word_chain, @@ -621,11 +424,10 @@ static void command_processing(struct param_type *params,  {      char **cmdline = NULL; -    /* and odd number of double quotes  */ +    /* odd number of double quotes  */      if(!is_double_quotes_pair(*params)) { -        print_error(); -        reset_params(params, current_mode, word_chain, cmdlines, tmp_word); -        show_invitation(); +        params->wrong_command = err_odd_double_quotes; +        goto clean;          return;      }      if(filename_waiting(params)) { @@ -635,7 +437,7 @@ static void command_processing(struct param_type *params,              if(params->tokens == '>' || params->tokens == append)                  add_filename(tmp_word, params);              else if(params->tokens == '<') { -                fprintf(stderr, "read in the last pipline element\n"); +                params->wrong_command = err_redirect_stream_in_pipeline;                  goto clean;              }          } else @@ -643,39 +445,15 @@ static void command_processing(struct param_type *params,      } else if(params->empty_word_flag || params->is_word)          add_word(word_chain, tmp_word, params); -#if 0 -    if(params->empty_word_flag || params->is_word) { -        if(filename_waiting(params)) { -            if(excessive_words(ch, params)) { -                fprintf(stderr, "too many args\n"); -                goto clean; -            } -            if(params->pipeline) { -                if(params->tokens == '>' || params->tokens == append) -                    add_filename(tmp_word, params); -                else if(params->tokens == '<') { -                    fprintf(stderr, "read in the last pipline element\n"); -                    goto clean; -                } -            } else -                add_filename(tmp_word, params); -        } else -            add_word(word_chain, tmp_word, params); - -    } else if(filename_waiting(params)) { -        fprintf(stderr, "filename expected\n"); -        goto clean; -    } -#endif -      if((params->tokens == and || params->tokens == or) &&              params->last_execution_status == 1) { +        /* ??? */          fprintf(stderr, "cannot be performed\n");          return;      }      if(word_chain->first == NULL) { -        fprintf(stderr, "empty command\n"); +        params->wrong_command = err_empty_command;          goto clean;      } @@ -684,26 +462,12 @@ static void command_processing(struct param_type *params,      run_external_program(word_chain, cmdlines, params);  clean: +    error_identification(params);      if(params->tokens == '&' || params->tokens == 0 || ch == new_line)          show_invitation();      reset_params(params, current_mode, word_chain, cmdlines, tmp_word);  } -#if 0 -static int is_empty_word(int ch, struct param_type params) -{ -    return (ch == whitespace || ch == tab) && !params.is_word && -            params.empty_word_flag; -} - -static int command_execution_condition(struct param_type *params) -{ -    return -        (!filename_waiting(params) && !params->pipeline) || -        (params->pipeline && params->tokens == '&'); -} -#endif -  static void word_separation_processing(int ch, struct param_type *params,                                         enum modes *current_mode,                                         struct w_queue *word_chain, @@ -735,6 +499,7 @@ static void word_separation_processing(int ch, struct param_type *params,          return;      }      if(params->wrong_command) { +        error_identification(params);          clean_input_buffer();          reset_params(params, current_mode, word_chain, cmdlines, tmp_word);          show_invitation(); @@ -742,9 +507,9 @@ static void word_separation_processing(int ch, struct param_type *params,      }      if(check_separation(ch, *params)) {          if(excessive_words(ch, params)) { +            error_identification(params);              clean_input_buffer();              reset_params(params, current_mode, word_chain, cmdlines, tmp_word); -            fprintf(stderr, "too many args\n");              show_invitation();              return;          } @@ -760,20 +525,6 @@ static void word_separation_processing(int ch, struct param_type *params,      add_letter(ch, tmp_word, params);  } -#if 0 -static int escape_double_quotes_or_backslash(int ch, struct param_type params) -{ -    return params.escape_sequences && -        (ch == double_quotes || ch == backslash); -} - -static int double_quotes_again(int ch, struct param_type params) -{ -    return ch == double_quotes && !params.is_word && -        params.stored_symbol == '"'; -} -#endif -  static void whole_word_processing(int ch, struct param_type *params,                                    enum modes *current_mode,                                    struct w_queue *word_chain, | 
