0

I'm currently programming a shell in C and I am stuck on the parsing function. At the moment I have a 'shell_readLine ()' function and a 'shell_split_line ()' function. I would like to improve the splitLine function so that it takes into account redirects such as: '|', '<' or '>'. Currently, only spaces serve as delimiters. I do not know where to start.

shell_readLine fonction :

char *shell_readLine(void)
{
    int buffsize = SHELL_RL_BUFFSIZE;
    int position = 0;
    char *buffer = malloc(sizeof(char) * buffsize);
    int c;
    if(!buffer) {
        fprintf(stderr, "shell: allocation error\n");
        exit(EXIT_FAILURE);
    }
    while(1) {
        // Read a character
        c = getchar();
        // If EOF, replace with null and return
        if(c == EOF || c == '\n') {
            buffer[position] = '\0';
            return buffer;
        } else {
            buffer[position] = c;
        }
        position++;
        // Check if we have exceeded the buffer and reallocate if necessary
        if(position >= buffsize) {
            buffsize += SHELL_RL_BUFFSIZE;
            buffer = realloc(buffer, buffsize);
            if(!buffer) {
                fprintf(stderr, "shell: allocation error\n");
                exit(EXIT_FAILURE);
            }
        }
    }
}

And my shell_split_line fonction :

/*
 *  Does not allow quoting or backslash escaping in command line args
 */
char **shell_split_line(char *line) {
    int buffsize = SHELL_TOK_BUFFSIZE, position = 0;
    char **tokens = malloc(buffsize * sizeof(char *));
    char *token;
    if(!tokens) {
        fprintf(stderr, "shell: allocation error\n");
        exit(EXIT_FAILURE);
    }
    token = strtok(line, SHELL_TOK_DELIM);
    while(token != NULL) {
        tokens[position] = token;
        position++;
        if(position >= buffsize) {
            buffsize += SHELL_TOK_BUFFSIZE;
            tokens = realloc(tokens, buffsize * sizeof(char *));
            if(!tokens) {
                fprintf(stderr, "shell: allocation error\n");
                exit(EXIT_FAILURE);
            }
        }
        token = strtok(NULL, SHELL_TOK_DELIM);
    }
    tokens[position] = NULL;
    return tokens;
}

Thanks in advance for your advices and ideas. I do not really know where to start and even how to make this. It's my first shell ever and i'm not a pro of C language.

n'golo
  • 1
  • 3
    You need a more elaborate tokenizer than you can easily write with just `strtok`. You _could_ add `|`, `<` etc. to the delimiter, but then they'd get chomped and you want to keep them. If you don't want to just use [flex](https://en.wikipedia.org/wiki/Flex_(lexical_analyser_generator)) or some other existing lexer, you can write a little finite state machine that classifies characters one-by-one as identifiers, special characters or whitespace. – Useless Jun 28 '21 at 11:56
  • @Useless ok thank you i'll inquire about lexers and flex – n'golo Jun 28 '21 at 12:03
  • One trivial suggestion: write a malloc wrapper that calls exit() rather than repeating that code in multiple places. Minimize duplicated code. – William Pursell Jun 28 '21 at 12:23
  • @Useless https://stackoverflow.com/questions/5491775/how-to-write-a-shell-lexer-by-hand on this stack topic, they talked about code generators for the rules. Have you heard about that ? – n'golo Jun 28 '21 at 12:25
  • Yep: flex _is_ a code generator. It takes a specification and produces C code. Similarly, if you want to write a formal grammar for your shell, you could use Bison to generate C code for that. – Useless Jun 28 '21 at 12:34
  • `shell_readLine` could also be enhanced to handle editing and history navigation. – fpiette Jun 28 '21 at 12:47
  • @n'golo - I think the most sensible next step, before you tackle redirection and pipes, is to implement quoting, so you'd have to make up your mind how you want to quote the spaces. – Armali Jun 28 '21 at 15:00

0 Answers0