Last active
September 24, 2017 05:25
-
-
Save vizv/9710508 to your computer and use it in GitHub Desktop.
vsh (VShell)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* File: a1p1.c | |
* Author: Wenxuan Zhao 100108743 | |
* Date: 2013/01/22 | |
* Version: 1.0 | |
* | |
* Purpose: vsh (V-Shell) first implementation! include only buildin function | |
* `exit`... | |
* TODO: > Simplify the error output message | |
* > Modulize the codes | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#define INIT_SIZE 1 | |
#define ERR_NULL_POINTER -1 | |
#define ERR_OUT_OF_MEMORY -1 | |
#define STR_PROMPT "Yo? " | |
#define EXIT_CMD_NOT_FOUND 255 | |
/* Abstract List */ | |
typedef struct | |
{ | |
void *els; | |
int n_used; | |
int n_alloc; | |
int els_size; | |
} lst_t, *lst_tp; | |
/* | |
* Name: new_lst | |
* Purpose: create a new abstruct list | |
* Arguments: given the pointer to the pointer of list, and the block size of | |
* one element | |
* Output: none | |
* Modifies: the pointer of list | |
* Returns: status code | |
* Assumptions: none | |
* Bugs: none | |
* Notes: none | |
*/ | |
int | |
new_lst(lst_tp *l, size_t blocksize) | |
{ | |
/* free existing list & elements in it */ | |
if (*l != NULL) | |
{ | |
if ((*l)->els != NULL) | |
free((*l)->els); | |
free(*l); | |
} | |
/* attampt to build a new list */ | |
lst_tp lst = malloc(sizeof(lst_tp)); | |
if (lst != NULL) | |
{ | |
lst->els = malloc(blocksize * INIT_SIZE); | |
if (lst->els != NULL) | |
{ | |
lst->n_used = 0; | |
lst->n_alloc = INIT_SIZE; | |
lst->els_size = blocksize; | |
*l = lst; | |
return 0; | |
} | |
} | |
return ERR_OUT_OF_MEMORY; | |
} | |
/* | |
* Name: lst_resize | |
* Purpose: resize the list according to it's current size | |
* Arguments: given the pointer of list to be resized | |
* Output: none | |
* Modifies: the size of list | |
* Returns: status code | |
* Assumptions: none | |
* Bugs: none | |
* Notes: none | |
*/ | |
int | |
lst_resize(lst_tp l) | |
{ | |
if (l == NULL) | |
return ERR_NULL_POINTER; | |
if (l->n_alloc > 3 * l->n_used || l->n_alloc == l->n_used) | |
{ | |
void *newels = realloc(l->els, l->n_alloc * l->els_size * 2); | |
if (newels == NULL) | |
return ERR_OUT_OF_MEMORY; | |
l->n_alloc *= 2; | |
l->els = newels; | |
} | |
return 0; | |
} | |
/* | |
* Name: lst_append_char | |
* Purpose: append a char to the list | |
* Arguments: given the pointer of list, and the char to be append | |
* Output: none | |
* Modifies: the element in the list | |
* Returns: status code | |
* Assumptions: none | |
* Bugs: none | |
* Notes: none | |
*/ | |
int | |
lst_append_char(lst_tp l, char c) | |
{ | |
int ret; | |
if ((ret = lst_resize(l))) | |
return ret; | |
char *p = l->els; | |
p[l->n_used++] = c; | |
return 0; | |
} | |
/* | |
* Name: lst_get_char | |
* Purpose: get a char from the list | |
* Arguments: given the pointer of list, and index of the char | |
* Output: none | |
* Modifies: none | |
* Returns: the pointer to the char | |
* Assumptions: none | |
* Bugs: TODO index unchecked! | |
* Notes: none | |
*/ | |
char * | |
lst_get_char(const lst_tp l, int i) | |
{ | |
char *p = l->els; | |
return &p[i]; | |
} | |
/* | |
* Name: lst_append_str | |
* Purpose: append a char string to the list | |
* Arguments: given the pointer of list, and the pointer of the char string | |
* to be append | |
* Output: none | |
* Modifies: the element in the list | |
* Returns: status code | |
* Assumptions: none | |
* Bugs: none | |
* Notes: none | |
*/ | |
int | |
lst_append_str(lst_tp l, char *s) | |
{ | |
int ret; | |
if ((ret = lst_resize(l))) | |
return ret; | |
char **p = l->els; | |
p[l->n_used++] = s; | |
return 0; | |
} | |
/* | |
* Name: lst_get_str | |
* Purpose: get the pointer to a char string from the list | |
* Arguments: given the pointer of list, and index of the char string | |
* Output: none | |
* Modifies: none | |
* Returns: the pointer to the pointer of char string | |
* Assumptions: none | |
* Bugs: TODO index unchecked! | |
* Notes: none | |
*/ | |
char ** | |
lst_get_str(const lst_tp l, int i) | |
{ | |
char **p = l->els; | |
return &p[i]; | |
} | |
/* | |
* Name: show_prompt | |
* Purpose: output the prompt to the standard output | |
* Arguments: none | |
* Output: the prompt | |
* Modifies: none | |
* Returns: none | |
* Assumptions: none | |
* Bugs: none | |
* Notes: TODO implement various prompt string using $PS1 | |
*/ | |
void | |
show_prompt() | |
{ | |
printf(STR_PROMPT); | |
} | |
/* | |
* Name: run_builtin | |
* Purpose: attampt to run the builtin command | |
* Arguments: the executable file and the argument list | |
* Output: none | |
* Modifies: none | |
* Returns: none | |
* Assumptions: none | |
* Bugs: none | |
* Notes: TODO implement more builtin command | |
*/ | |
int | |
run_builtin(const char *exec, char **argv) | |
{ | |
if (!strcmp(exec, "exit")) | |
exit(0); | |
return 0; | |
} | |
int | |
main(int argc, char *argv[]) | |
{ | |
int i, ret; | |
pid_t pid; | |
lst_tp cmd_buffer = NULL, args_list = NULL; | |
if ((ret = new_lst(&cmd_buffer, sizeof(char)))) | |
{ | |
fprintf(stderr, "%s: FATAL ERROR - Cannot create " | |
"command buffer (%d).\n", argv[0], ret); | |
return EXIT_FAILURE; | |
} | |
show_prompt(); | |
int c; | |
for (;;) | |
{ | |
c = getchar(); | |
switch(c) | |
{ | |
case '\n': | |
/* skip if nothing was inputed */ | |
if (!cmd_buffer->n_used) | |
{ | |
show_prompt(); | |
break; | |
} | |
/* make a valid char string */ | |
if ((ret = lst_append_char(cmd_buffer, '\0'))) | |
{ | |
fprintf(stderr, "%s: FATAL ERROR - Something goes wrong " | |
"while handling input (%d).\n", argv[0], ret); | |
return EXIT_FAILURE; | |
} | |
/* make a new argument list */ | |
if ((ret = new_lst(&args_list, sizeof(char *)))) | |
{ | |
fprintf(stderr, "%s: FATAL ERROR - Cannot create " | |
"arguments list (%d).\n", argv[0], ret); | |
return EXIT_FAILURE; | |
} | |
/* build exec and arguments */ | |
lst_append_str(args_list, cmd_buffer->els); | |
for (i = 0; *lst_get_char(cmd_buffer, i) != '\0'; i++) | |
{ | |
if (*lst_get_char(cmd_buffer, i) == ' ') | |
{ | |
*lst_get_char(cmd_buffer, i) = '\0'; | |
lst_append_str(args_list, lst_get_char(cmd_buffer, i + 1)); | |
} | |
} | |
lst_append_str(args_list, NULL); | |
char *exec = cmd_buffer->els; | |
char **args = args_list->els; | |
/* run built-in commands */ | |
if (!run_builtin(exec, args)) | |
{ | |
/* if failed, run external command */ | |
pid = fork(); | |
if (!pid) | |
return (ret = execvp(exec, args)); | |
/* wait until finished */ | |
waitpid(pid, &ret, 0); | |
if (WIFEXITED(ret)) | |
{ | |
if(WEXITSTATUS(ret) == EXIT_CMD_NOT_FOUND) | |
fprintf(stderr, "%s: command not found\n", exec); | |
} | |
} | |
show_prompt(); | |
if ((ret = new_lst(&cmd_buffer, sizeof(char *)))) | |
{ | |
fprintf(stderr, "%s: FATAL ERROR - Cannot create " | |
"command buffer (%d).\n", argv[0], ret); | |
return EXIT_FAILURE; | |
} | |
break; | |
case EOF: | |
if (!cmd_buffer->n_used) | |
{ | |
printf("exit\n"); | |
return EXIT_SUCCESS; | |
} | |
break; | |
default: | |
if ((ret = lst_append_char(cmd_buffer, c))) | |
{ | |
fprintf(stderr, "%s: FATAL ERROR - Something goes wrong " | |
"while handling input (%d).\n", argv[0], ret); | |
return EXIT_FAILURE; | |
} | |
} | |
} | |
fprintf(stderr, "%s: WARNING - Unexpected Closing.\n", argv[0]); | |
return EXIT_FAILURE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment