question archive Add a new built-in alias command that allows you to define a shortcut for commands by essentially defining a new command that substitutes a given string for some command, perhaps with various flags/options

Add a new built-in alias command that allows you to define a shortcut for commands by essentially defining a new command that substitutes a given string for some command, perhaps with various flags/options

Subject:Computer SciencePrice:4.86 Bought15

Add a new built-in alias command that allows you to define a shortcut for commands by essentially defining a new command that substitutes a given string for some command, perhaps with various flags/options. The syntax is as follows: alias alias_name='command'. For example, you can define an alias with alias ll='ls -al', so that the user can then enter ll at the prompt to execute the ls -al command. Specifying alias with no arguments should display a list of all existing aliases. You may remove a single alias with the command alias -r alias_name or all defined aliases with alias -c.

Based on the code below:

 

//#define _GNU_SOURCE

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/wait.h>

#include <unistd.h>

#include <pwd.h>

#include "errno.h"

//macro for number of cmd line args

static const int MAX_ARGC = 100;

//api to crate child process using fork and execvp

void execute (char *const args[]);

int main(int argc, char *argv[])

{

    char *line = NULL;

    size_t len;

    char *shell_argv[MAX_ARGC +1];

    int shell_argc;

    char *pos;

    int should_run =1;

    //infinite loop for receive inputs from user

    while (should_run)

    {

        //shell prompt

        printf("minor2> ");

        if (getline(&line, &len, stdin) <= 0)

        {

            printf("n");

            break;

        }

        //if user enters exit, set should_run to 0 to break the loop

        if (strcmp(line, "quitn") == 0)

        {

            should_run=0;

            continue;

        }

        //if user press enter key, goes to next shell prompt

        if (strcmp(line, "n") == 0)

        {

            continue;

        }

        pos=line;

        //split the arguments to tokens

        for (shell_argc=0; shell_argc<=MAX_ARGC; shell_argc++)

        {

            while(*pos == ' ' || *pos == 't')

                ++pos;

            if(*pos == 'n' || *pos == '')

                break;

            shell_argv[shell_argc] = pos;

            while (*pos != ' ' && *pos != 't' && *pos != 'n' && *pos != '')

            {

                ++pos;

            }

            if (*pos != '')

                *(pos++)='';

        }

        shell_argv[shell_argc]=NULL;

        //if user enters system command like "cd", no need to execute via exec call

        if((strcmp(shell_argv[0],"cd") == 0) && (shell_argc <= 2))

        {

            char buff[128]={'',};

            if (shell_argc == 2)

            {

                snprintf(buff, 127, "%s", shell_argv[1]);

            }

                else

                {

                    //if the user enrersonly "cd" command, then goto home direcotry

                    const char *homedir;

                    if ((homedir = getenv("HOME")) == NULL)

                    {

                    homedir = getpwuid(getuid())->pw_dir;

                    }

                    snprintf(buff, 127, "%s", homedir);

                }

            chdir(buff);

            continue;

        }

        //pass the user enterd arguments

        execute(shell_argv);

    }

    //free the memory holding user entered arguments

    free(line);

    exit(0);

}

void execute (char *const args[])

{

    int i;

    //set to 1, to enable debugging

    #if 0

    printf("*** Entered:");

    for (i=0;args[i]!=NULL;i++)

    printf(" %s", args[i]);

    printf(" (%d words)n", i);

    #endif

    //call fork to create child process

    pid_t pid = fork();

    int status=0;

    if (pid == -1) // error handling

    {

        printf("Fork Failedn");

        return;

    }

    int ret=0;

    if(pid == 0) // child process

    {

        //invoke execvp to run the commands

        execvp(args[0], args);

        printf("Command not foundn");

        exit(1);

    }

        else if(pid > 0) // parent process

        {

            /* See what was the cause of the child processes' demise. */

            int status=0;

            //wait for child process to get completed

            wait(&status);

            int exitStatus = WEXITSTATUS(status);

            //if a process is exited normally, it comes here

            if(WIFEXITED(status))

            {

                //if its exit status is 2, it means command not found

                if (exitStatus==2)

                {

                    printf("* Process %d exited with code 2n", pid);

                }

            }

            //when a process is crashed, it comes here and it exit status is 0

                else if(WIFSIGNALED(status))

                {

                    if (exitStatus==0)

                    {

                        printf("* Process %d crashed: Segmentation faultn", pid);

                    }

                }

                    else

                    {

                        printf("Mysteriously vanished. %dn", WEXITSTATUS(status));

                    }

        }

    return;

}

pur-new-sol

Purchase A New Answer

Custom new solution created by our subject matter experts

GET A QUOTE

Answer Preview

shell.c:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#define PS1 "~> "
#define BUFFER_SIZE 1024
#define ALIAS_USAGE \
    "Usage of alias:\n" \
    "alias                      - Display a list of all aliases\n" \
    "alias alias_name='command' - Add a new alias\n" \
    "alias -r alias_name        - Remove a single alias\n" \
    "alias -c                   - Remove all aliases" \

typedef struct Alias alias_t;
typedef struct Alias* alias_ptr_t;

// singly linked list to hold a list of alias names and commands
struct Alias
{
    char* name;
    char* command;
    alias_ptr_t next;
};

// returns a pointer to a heap allocated alias struct
// filled with a copy of the passed name and command
alias_ptr_t alias_create(char* name, char* command)
{
    alias_ptr_t new_alias_ptr = (alias_ptr_t) malloc(sizeof(alias_t));

    *new_alias_ptr =
        (alias_t) {
            .name = name,
            .command = command,
            .next = NULL
        };

    return new_alias_ptr;
}

// frees the particular alias struct
void alias_free(alias_ptr_t alias_ptr)
{
    if(alias_ptr != NULL)
    {
        free(alias_ptr->name);
        free(alias_ptr->command);

        *alias_ptr =
            (alias_t) {
                .name = NULL,
                .command = NULL,
                .next = NULL
            };

        free(alias_ptr);
    }
}

// recursively frees the entire alias data structure with the
// passed argument as the head of the list
alias_ptr_t alias_destroy(alias_ptr_t alias_ptr)
{
    if(alias_ptr)
    {
        alias_destroy(alias_ptr->next);
        alias_free(alias_ptr);
    }

    return NULL;
}

// removes elements from the alias list that have a matching name
// and returns the new head of the list
alias_ptr_t alias_remove(alias_ptr_t alias_ptr, const char* name)
{
    if(alias_ptr == NULL)
    {
        // empty list
        return NULL;
    }

    if(strcmp(alias_ptr->name, name) == 0)
    {
        // first element matches
        alias_ptr_t next = alias_ptr->next;
        alias_free(alias_ptr);
        return next;
    }

    // removing from the middle to the end of the list
    alias_ptr_t iterator = alias_ptr;

    while(iterator->next != NULL)
    {
        if(strcmp(iterator->next->name, name) == 0)
        {
            alias_ptr_t next = iterator->next->next;
            alias_free(iterator->next);
            iterator->next = next;
            break;
        }

        iterator = iterator->next;
    }

    return alias_ptr;
}

// adds a new (name, command) pair to the list of aliases
// by first removing any element with the passed name and
// returns the new head of the list of aliases
alias_ptr_t alias_add(alias_ptr_t alias_ptr, const char* name, const char* command)
{
    alias_ptr = alias_remove(alias_ptr, name);

    alias_ptr_t new_alias_ptr = alias_create(strdup(name), strdup(command));

    if(alias_ptr == NULL)
    {
        // list was empty
        return new_alias_ptr;
    }

    // going to the end of the alias list
    alias_ptr_t end_ptr = alias_ptr;
    while(end_ptr->next)
        end_ptr = end_ptr->next;

    // adding new_alias_ptr to the end
    end_ptr->next = new_alias_ptr;

    return alias_ptr;
}

// recursively displays the entire alias data structure
void alias_display(const alias_ptr_t alias_ptr)
{
    if(alias_ptr)
    {
        printf("%s=\"%s\"\n", alias_ptr->name, alias_ptr->command);
        alias_display(alias_ptr->next);
    }
}

// recursively searches for a command with the passed name
// in the entire alias data structure and returns NULL if
// not found
char* alias_query(const alias_ptr_t alias_ptr, const char* name)
{
    if(alias_ptr == NULL)
    {
        // not found
        return NULL;
    }

    if(strcmp(alias_ptr->name, name) == 0)
    {
        // match found
        return alias_ptr->command;
    }

    // search in the rest
    return alias_query(alias_ptr->next, name);
}

// executes non-alias-prefixed commands using system
void execute_other_command(char* command, const alias_ptr_t alias_ptr)
{
    char* query = alias_query(alias_ptr, command);

    if(query != NULL)
    {
        command = query;
    }

    system(command);
}

// executes alias commands
alias_ptr_t execute_alias_command(char* command, alias_ptr_t alias_ptr)
{
    bool incorrect_usage = false;

    if(strncmp(command, "alias -", strlen("alias -")) == 0)
    {
        // alias with options
        if(command[7] == 'c')
        {
            // remove all aliases
            alias_ptr = alias_destroy(alias_ptr);
        }
        else if(command[7] == 'r')
        {
            // remove a single alias
            char alias_name[BUFFER_SIZE];
            sscanf(command, "alias -r %s", alias_name);
            alias_ptr = alias_remove(alias_ptr, alias_name);
        }
        else
        {
            incorrect_usage = true;
        }
    }
    else if(command[5] != '\0')
    {
        // set alias
        char* alias_name;
        char* alias_command;

        // start of alias name
        alias_name = command + 6;

        // finding assignment operator
        char* iterator = alias_name + 1;
        bool assignment_found = false;
        while(*iterator != '\0')
        {
            if(*iterator == '=')
            {
                assignment_found = true;
                break;
            }

            ++iterator;
        }

        if(assignment_found)
        {
            *iterator = '\0'; // replacing assignment operator with '\0'
            ++iterator;

            // quote at start of alias command
            if(*iterator == '\'')
            {
                alias_command = ++iterator;

                // finding ending quote after alias command
                bool quote_found = false;
                while(*iterator != '\0')
                {
                    if(*iterator == '\'')
                    {
                        quote_found = true;
                        break;
                    }

                    ++iterator;
                }

                if(quote_found)
                {
                    *iterator = '\0'; // replacing quote with '\0'

                    // adding alias
                    alias_ptr = alias_add(alias_ptr, alias_name, alias_command);
                }
                else
                {
                    incorrect_usage = true;
                }
            }
            else
            {
                incorrect_usage = true;
            }
        }
        else
        {
            incorrect_usage = true;
        }
    }
    else
    {
        // display aliases
        alias_display(alias_ptr);
    }

    if(incorrect_usage)
    {
        // incorrect usage
        puts("Incorrect usage.");
        puts(ALIAS_USAGE);
    }
gg
    return alias_ptr;
}

int main()
{
    // declaring the alias
    alias_ptr_t alias_ptr = NULL;

    // declaring the input buffer
    char command[BUFFER_SIZE];

    // shell loop
    for(;;)
    {
        // printing shell prefix
        printf(PS1);

        // reading in the command
        if(fgets(command, BUFFER_SIZE, stdin) == NULL)
        {
            break;
        }

        // removing newline
        command[strlen(command) - 1] = '\0';

        // routing commands
        if(strncmp(command, "alias", strlen("alias")) == 0)
        {
            alias_ptr = execute_alias_command(command, alias_ptr);
        }
        else
        {
            execute_other_command(command, alias_ptr);
        }
    }

    // destroying the alias
    alias_ptr = alias_destroy(alias_ptr);

    return 0;
}

Please see the attached file for the complete solution

Related Questions