Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "gnu17",
"cppStandard": "gnu++17",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"files.associations": {
"readline.h": "c"
}
}
30 changes: 30 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
CC = gcc

# shell headers, code, and targets
INC=src/include
CPPFLAGS=src/lib
OBJDIR=build/dist

# commands code and libs
CMDIR=src/code
BINDIR=build/bin

objects = $(addprefix $(OBJDIR)/, basic.o internal.o env.o shell.o)
cmds = $(addprefix $(BINDIR)/, echo hello ls)


CFLAGS = -I$(CPPFLAGS)
LDFLAGS = -L$(OBJDIR) -lreadline # -Lbuild/dist

shell: $(objects)
$(CC) $(objects) $(LDFLAGS) -o ./build/shell

$(OBJDIR)/%.o: $(CPPFLAGS)/%.c
$(CC) $(CFLAGS) -I$(INC) -c -o $@ $<

$(BINDIR)/%: $(CMDIR)/%.c
$(CC) -o $@ $<

commands: $(cmds)

.PRECIOUS: %.o
30 changes: 24 additions & 6 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
# Simple shell

## dependencies

to install readline, feel free to edit it to use `fgets` or `scanf` refer to this [link](https://stackoverflow.com/questions/17294809/reading-a-line-using-scanf-not-good) for reference on both.

```bash
sudo apt-get install libreadline6 libreadline6-dev
```

## Features

1. external commands
1. ls
2. echo
3. hello (deprecated, before being released 🤣🤣)
2. internal commands
1. hello (yes again, this is the one that will actually run)
2. cd
3. env
4. set

## Make from source

to compile the code

```bash
mkdir build
mkdir build/bin
gcc shell.c -lreadline -o ./build/shell
gcc ./lib/echo.c -o ./build/bin/echo
make shell
make commands
```

to run the command
## Run

```bash
cd build
./shell
./build/shell
```

You need to change into the build directory for the path to take actual effect
## Notes

This code is developed to simulate how I expect an actual shell works. any resmeblance between this and reality is mere coincidence.
Empty file removed lib/cd.c
Empty file.
Empty file removed lib/ls.c
Empty file.
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions src/code/hello.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>

int main() {
printf("Hello world");
return 0;
}
27 changes: 27 additions & 0 deletions src/code/ls.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>

int main(int argc, char* argv[])
{
DIR *mydir;
struct dirent *myfile;
struct stat mystat;
char buf[512];

char* path;
if (argc >= 2) path = argv[1];
else path = ".";
mydir = opendir(path);

while((myfile = readdir(mydir)) != NULL)
{
sprintf(buf, "%s/%s", path, myfile->d_name);
stat(buf, &mystat);
printf("%zu\t%s\n",mystat.st_size, myfile->d_name);
}
closedir(mydir);
}
7 changes: 7 additions & 0 deletions src/include/basic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef BASIC_H
#define BASIC_H

int parse_command(char* in, char** argv);
int run_command(char** args);

#endif
14 changes: 14 additions & 0 deletions src/include/env.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef ENV_H
#define ENV_H

void init_env();

char* get_env_variable(char* );

int set_env_variable(char* , char *);

void disp_env();

char* find_command(char* command);

#endif
8 changes: 8 additions & 0 deletions src/include/internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef INTERNAL_H
#define INTERNAL_H

int is_internal(char* );

int run_internal_command(int , int , char** );

#endif
33 changes: 2 additions & 31 deletions shell.c → src/lib/basic.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <readline/readline.h>
#include <readline/history.h>

#define BIN_PATH "./bin/"

int parse_command(char* in, char** argv) {
int argc = 0, reader_idx = 0, writer_idx, len = strlen(in);
Expand All @@ -32,40 +28,15 @@ int parse_command(char* in, char** argv) {
// skip trailing spaces
while(in[reader_idx] == ' ') ++reader_idx; // skip spaces
}
argv[argc] = NULL;

return argc;
}

char* find_command(char* command) {
char* isPath = strchr(command, '/');
char* path;
if (isPath == NULL) {
path = strcat(strdup(BIN_PATH), command);
} else {
path = command;
}
return path;
}

int run_command(char** args) {
int rc = fork();
if (rc == 0) {
execvp(args[0], args); // runs word count
}
wait(NULL);
}

int main(int argc, char *argv[]) {
while (1) {
char* in = readline(">$ ");
char** command = (char**) malloc(100 * sizeof(char*));
int args_count = parse_command(in, command);
printf("Command recieved: %s, with %d args\n", command[0], args_count - 1);
int i = 0;
for (; i < args_count;i++) printf("argument %d: %s\n", i, command[i]);
char* command_path = find_command(command[0]);
command[0] = command_path;
run_command(command);
}
return 0;
}
68 changes: 68 additions & 0 deletions src/lib/env.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#include "env.h"

#define PATH "/home/aim97/os/MyShell/build/bin/"

struct Env_variable {
char* name;
char* value;
};

static int variables_count = 0;
static struct Env_variable* env_variables[100];

static void add_entry (char* name, char* value) {
env_variables[variables_count] = malloc(sizeof (struct Env_variable));
env_variables[variables_count]->name = name;
env_variables[variables_count]->value = value;
variables_count++;
}

void init_env() {
add_entry("PATH", PATH);
}

char* get_env_variable(char* name) {
int i = 0;
for(;i < variables_count;i++) {
if (!strcmp(env_variables[i]->name, name)) {
return env_variables[i]->value;
}
}
return NULL;
}

int set_env_variable(char* name, char* value) {
int i = 0;
for(;i < variables_count;i++) {
if (!strcmp(env_variables[i]->name, name)) {
free(env_variables[i]->value);
env_variables[i]->value = value;
return 0;
}
}
add_entry(name, value);
return 0;
}

void disp_env() {
int i = 0;
for(;i < variables_count;i++) {
printf("%s %s\n",env_variables[i]->name, env_variables[i]->value);
}
}

char* find_command(char* command) {
char* isPath = strchr(command, '/');
char* path;
if (isPath == NULL) {
path = strcat(strdup(PATH), command);
} else {
path = command;
}
return path;
}
75 changes: 75 additions & 0 deletions src/lib/internal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#include "internal.h"
#include "env.h"

#define INTERNAL_COMMANDS_COUNT 4

struct Internal_command {
char* name;
int (*exec)(int argc, char* args[]);
};

static int get_cwd() {
char* v = (char*) malloc(sizeof (char)*1000);
char* ret = getcwd(v, 1000);
if (ret != NULL) {
printf("CWD: %s\n", v);
free(v);
return 0;
}
free(v);
return 1;
}

static int cd(int argc, char** args) {
if (argc == 0) {
return get_cwd();
}
return chdir(args[0]);
}

static int hello (int argc, char** args) {
printf("hello again\n");
return 0;
}


int env(int argc, char** args) {
disp_env();
return 0;
}

int set(int argc, char** args) {
if (argc < 2) {
return 1;
}
set_env_variable(args[0], args[1]);
return 0;
}

static struct Internal_command internal_commands[] = {
{ "env", &env },
{ "cd", &cd },
{ "set", &set },
{ "hello", &hello }
};

int is_internal(char* command) {
int i = 0,idx = -1;
for (;i < INTERNAL_COMMANDS_COUNT;i++) {
int ret = strcmp(internal_commands[i].name, command);
if (ret == 0) {
idx = i;
break;
}
}
return idx;
}

int run_internal_command(int code, int argc, char** argv) {
return internal_commands[code].exec(argc, argv);
}
Loading