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
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;
}
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