Skip to content

Commit

Permalink
Added support for built-in commands that a shell needs
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielVukelich committed Nov 12, 2016
1 parent cf96645 commit 2411121
Show file tree
Hide file tree
Showing 13 changed files with 801 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CC=gcc
CFLAGS=-Wall -Werror -std=c99
OBJS=argbuild.o vsh.o
OBJS= err_handling.o trie/trie.o trie/intern.o builtin.o argbuild.o vsh.o
BINARY=vsh

.PHONY: clean all debug release
Expand Down
52 changes: 42 additions & 10 deletions argbuild.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
#include "argbuild.h"

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

void add_arg(char* argument, arg_t* args){
void add_arg(char* argument, arg_t* args, int len){
if(args->end != NULL){
arg_elt_t* last = args->end;
int al = last->arg_len;
if((al > 1) && (last->arg[al - 2] == '\\')){
//If the last char of the last arg was backslash
//then the slash should be replaced with
//a space character and then the arg to add
//should be added onto the end.
last->arg[al - 2] = ' ';
//Subtract one to account for removing 1 null
//terminator after concatenating
int newlen = al + len - 1;
char* newarg = malloc(sizeof(char) * newlen);
strncpy(newarg, last->arg, al);
//Add the new argument onto the end
char* newarg_offset = newarg + al - 1;
strncpy(newarg_offset, argument, len);
free(last->arg);
last->arg = newarg;
return;
}
}

arg_elt_t* toadd = malloc(sizeof(arg_elt_t));
toadd->arg = argument;
toadd->next = NULL;
toadd->arg_len = len;
if(args->end != NULL){
args->end->next = toadd;
}
Expand Down Expand Up @@ -34,7 +59,7 @@ arg_t* build_args(char* cmd, unsigned int cmd_max_len){

//Ignore multiple spaces between arguments
if(cmd[i] == ' ' && cmd[i + 1] == ' '){
continue;
continue;
}

char delineate = cmd[i];
Expand All @@ -54,7 +79,7 @@ arg_t* build_args(char* cmd, unsigned int cmd_max_len){
//terminator
cmd[i] = delineate;
//Now add the string to our linked list of arg elts
add_arg(arg_str, to_return);
add_arg(arg_str, to_return, new_str_siz);
//Make sub_start point to the next char after cmd[i], which is
//a space
sub_start = i + 1;
Expand All @@ -65,21 +90,28 @@ arg_t* build_args(char* cmd, unsigned int cmd_max_len){
return to_return;
}

char** get_args(arg_t* args, int* numargs){
int get_args(arg_t* args, char** argv_to_fill){
if(args->argc <= 0){
return NULL;
return -1;
}

char** to_return = malloc(sizeof(char) * (args->argc + 1));
*numargs = 0;
int numargs = 0;
for(arg_elt_t* it = args->first; it != NULL; it = it->next){
to_return[(*numargs)++] = it->arg;
argv_to_fill[numargs++] = it->arg;

//If the last non-null character in the last argument
//is a backslash, replace it with a space
if(it->next == NULL && it->arg[it->arg_len - 1] == '\\'){
it->arg[it->arg_len - 1] = ' ';
}

puts(argv_to_fill[numargs - 1]);
}

//The last elt in this array is a null pointer
to_return[args->argc] = '\0';
argv_to_fill[args->argc] = NULL;

return to_return;
return args->argc;
}

void free_args(arg_t* tofree){
Expand Down
3 changes: 2 additions & 1 deletion argbuild.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
typedef struct arg_elt{
struct arg_elt* next;
char* arg;
int arg_len;
} arg_elt_t;

typedef struct args{
Expand All @@ -13,7 +14,7 @@ typedef struct args{
} arg_t;

arg_t* build_args(char* cmd, unsigned int cmd_max_len);
char** get_args(arg_t* args, int* numargs);
int get_args(arg_t* args, char** argv_to_fill);
void free_args(arg_t* tofree);

#endif
69 changes: 69 additions & 0 deletions builtin.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "builtin.h"

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

#include "vsh.h"
#include "trie/trie.h"

static trie* cmd_map;

typedef int (*cmd_func_t)(int, char**);

typedef struct func_ary_elt{
cmd_func_t function;
char* cmd_name;
} func_ary_elt_t;

int shell_exit(int argc, char** argv){
running = 0;
return 0;
}

int change_directory(int argc, char** argv){
if(argc == 1){
//Return to ~ if home directory is set,
//or do nothing
puts("Home directory not set");
return 0;
}
int toreturn = chdir(argv[1]);
last_cmd_errno = errno;
if(toreturn){
errstr = strerror(last_cmd_errno);
}
return toreturn;
}

static func_ary_elt_t func_ary[] = {
{&shell_exit, "exit"},
{&change_directory, "cd"},
{NULL, NULL}
};

void init_builtin_commands(){
cmd_map = trie_create();
for(func_ary_elt_t* i = func_ary; i->function != NULL; ++i){
trie_insert(cmd_map, i->cmd_name, &(i->function));
}
}

int run_builtin_command(int argc, char** argv){
builtin_cmd_found = 1;
//You can't cast a function pointer as void*, but you
//can cast the pointer to a function pointer as void*
cmd_func_t* to_run = (cmd_func_t*) trie_search(cmd_map, argv[0]);
if(!to_run){
builtin_cmd_found = 0;
return 0;
}
cmd_func_t func_to_run = *to_run;
last_cmd_code = func_to_run(argc, argv);
return last_cmd_code;
}

void deinit_builtin_commands(){
trie_free(cmd_map);
}
8 changes: 8 additions & 0 deletions builtin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef BUILTIN_H
#define BUILTIN_H

void init_builtin_commands();
int run_builtin_command(int argc, char** argv);
void deinit_builtin_commands();

#endif
7 changes: 7 additions & 0 deletions err_handling.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "err_handling.h"
#include <stdio.h>
#include "vsh.h"

void print_error(){
fprintf(stderr, "%s: %s: %s\n", me, last_argv[0], errstr);
}
6 changes: 6 additions & 0 deletions err_handling.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef ERROR_HANDLING_H
#define ERROR_HANDLING_H

void print_error();

#endif
55 changes: 55 additions & 0 deletions trie/intern.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include <stdlib.h>
#include <string.h>
#include "trie.h"
#include "intern.h"

int intern_init(struct intern *pool)
{
pool->trie = trie_create();
return pool->trie == NULL ? -1 : 0;
}


static int visitor_free(const char *key, void *data, void *arg)
{
(void) key;
(void) arg;
free(data);
return 0;
}

int intern_free(struct intern *pool)
{
trie_visit(pool->trie, "", visitor_free, NULL);
return trie_free(pool->trie);
}

static void *inserter(const char *key, void *data, void *arg)
{
char **dup = arg;
if (data == NULL) {
*dup = malloc(strlen(key) + 1);
if (*dup != NULL)
strcpy(*dup, key);
return *dup;
} else {
return (*dup = data);
}
}

const char *intern(struct intern *pool, const char *string)
{
char *canonical = NULL;
trie_replace(pool->trie, string, inserter, &canonical);
return canonical;
}

const char *intern_soft(struct intern *pool, const char *string)
{
return trie_search(pool->trie, string);
}

size_t intern_count(struct intern *pool)
{
return trie_count(pool->trie, "");
}
58 changes: 58 additions & 0 deletions trie/intern.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#ifndef INTERN_H
#define INTERN_H

/**
* String Pool Library
*
* Interns and allocates internal copies of provided strings. The
* intern() function returns the canonical string for a given UTF-8,
* NUL-terminated C string. This provides two significant advantages:
*
* 1. Canonicalized strings compare correctly with ==. No strcmp() is
* required.
* 2. Strings are only ever allocated once. For this to work properly,
* canonicalized strings MUST be considered immutable.
*
* The underlying trie is intentionally exposed for direct access,
* should any sort of trie-specific functionality be required.
*/

struct intern {
trie *trie;
};

/**
* Initializes a new string intern string pool.
* @return 0 on success
*/
int
intern_init(struct intern *pool);

/**
* Frees all resources held by an intern string pool.
* @return 0 on success
*/
int
intern_free(struct intern *pool);

/**
* Retrieves the canonical string, inserting one if necessary.
* @return the canonical object for STRING, NULL on error
*/
const char *
intern(struct intern *pool, const char *string);

/**
* Get the canonical string without adding a new string to the pool.
* @return the canonical object for STRING, NULL if none exists
*/
const char *
intern_soft(struct intern *pool, const char *string);

/**
* @return the number of strings in this pool
*/
size_t
intern_count(struct intern *pool);

#endif
Loading

0 comments on commit 2411121

Please sign in to comment.