Initial commit
This commit is contained in:
commit
10d9c9dec9
9 changed files with 542 additions and 0 deletions
4
Makefile
Normal file
4
Makefile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
rush: rush.c color.c constants.h history.c
|
||||||
|
gcc -o rush rush.c color.c history.c
|
||||||
|
all:
|
||||||
|
rush
|
36
README.md
Normal file
36
README.md
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# rush
|
||||||
|
|
||||||
|
rush is a minimalistic shell for Unix systems written in C.
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
- gcc
|
||||||
|
|
||||||
|
# Building
|
||||||
|
```sh
|
||||||
|
$ make
|
||||||
|
```
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
```sh
|
||||||
|
$ ./rush
|
||||||
|
```
|
||||||
|
|
||||||
|
# Features
|
||||||
|
- Showing current time and directory with custom color
|
||||||
|
- syntax highlighting on valid commands using ANSI colors
|
||||||
|
- history navigation using up and down keys
|
||||||
|
|
||||||
|
# Todo Features
|
||||||
|
- Pipe
|
||||||
|
- stdin, stdout, stderr redirect
|
||||||
|
- background jobs
|
||||||
|
- editing using left and right arrow keys
|
||||||
|
- history command
|
||||||
|
- export command to setenv
|
||||||
|
- tab completion
|
||||||
|
|
||||||
|
# Credits
|
||||||
|
- [Tutorial - Write a shell in C](https://brennan.io/2015/01/16/write-a-shell-in-c/)
|
||||||
|
- [dash](https://github.com/danishprakash/dash)
|
||||||
|
- [Shell assignment](https://www.cs.cornell.edu/courses/cs414/2004su/homework/shell/shell.html)
|
||||||
|
- [khol](https://github.com/SanketDG/khol/)
|
22
color.c
Normal file
22
color.c
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// color str in place
|
||||||
|
|
||||||
|
void color_text(char str[], const char *color) {
|
||||||
|
int size = snprintf(NULL, 0, "\x1b[38;2;%sm%s\x1b[0m", color, str) + 1; // calculate size that is needed for colored string
|
||||||
|
if (size < 0) {
|
||||||
|
fprintf(stderr, "rush: snprintf failed\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
char *buf = malloc(size);
|
||||||
|
if (buf == NULL) {
|
||||||
|
fprintf(stderr, "rush: Memory allocation failed\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, size, "\x1b[38;2;%sm%s\x1b[0m", color, str); // format string to buf
|
||||||
|
strcpy(str, buf);
|
||||||
|
free(buf);
|
||||||
|
}
|
10
color.h
Normal file
10
color.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef COLOR_H_
|
||||||
|
#define COLOR_H_
|
||||||
|
|
||||||
|
const char *lavender = "174;174;255";
|
||||||
|
const char *pink = "255;210;239";
|
||||||
|
const char *blue = "137;180;250";
|
||||||
|
|
||||||
|
void color_text(char str[], const char *color);
|
||||||
|
|
||||||
|
#endif
|
9
constants.h
Normal file
9
constants.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef CONSTANTS_H_
|
||||||
|
#define CONSTANTS_H_
|
||||||
|
|
||||||
|
#define HISTFILE ".rush_history" // history file name
|
||||||
|
#define TOK_BUFSIZE 64 // buffer size of each token
|
||||||
|
#define RL_BUFSIZE 1024
|
||||||
|
#define TOK_DELIM " \t\r\n\a" // delimiter for token
|
||||||
|
|
||||||
|
#endif
|
91
history.c
Normal file
91
history.c
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
|
||||||
|
FILE *history_file;
|
||||||
|
char *histfile_path;
|
||||||
|
int cmd_count = 0;
|
||||||
|
|
||||||
|
void check_history_file() {
|
||||||
|
char *env_home;
|
||||||
|
env_home = getenv("XDG_CONFIG_HOME");
|
||||||
|
if (env_home == NULL) {
|
||||||
|
// fallback to $HOME if $XDG_CONFIG_HOME is null
|
||||||
|
env_home = getenv("HOME");
|
||||||
|
}
|
||||||
|
int env_home_len = strlen(env_home);
|
||||||
|
int histfilename_len = strlen(HISTFILE);
|
||||||
|
int path_len = env_home_len + histfilename_len + 2; // 2 for slash and null byte
|
||||||
|
histfile_path = malloc(sizeof(char) * path_len);
|
||||||
|
// concatenate home and history file name to a path
|
||||||
|
strcat(histfile_path, env_home);
|
||||||
|
strcat(histfile_path, "/");
|
||||||
|
strcat(histfile_path, HISTFILE);
|
||||||
|
histfile_path[path_len] = '\0';
|
||||||
|
if (access(histfile_path, F_OK) != 0) { // check for file existence
|
||||||
|
history_file = fopen(histfile_path, "w"); // read and write, if doesn't exist, create
|
||||||
|
if (history_file == NULL) {
|
||||||
|
fprintf(stderr, "rush: Error opening history file\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
fclose(history_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_command_history(char *command) {
|
||||||
|
history_file = fopen(histfile_path, "a+");
|
||||||
|
if (history_file == NULL) {
|
||||||
|
fprintf(stderr, "rush: Error opening history file\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
int cmd_len = strlen(command);
|
||||||
|
command[cmd_len] = '\n'; // put new line feed to split commands
|
||||||
|
// ptr to first obj, size of each obj, number of obj, file ptr
|
||||||
|
fwrite(command, sizeof(char), cmd_len + 1, history_file);
|
||||||
|
fclose(history_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *read_command(int direction) {
|
||||||
|
history_file = fopen(histfile_path, "rb"); // read binary mode
|
||||||
|
if (history_file == NULL) {
|
||||||
|
fprintf(stderr, "rush: Error opening history file\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
// normal bufsize is 1024, we serach for 1025 bytes for new line feed
|
||||||
|
int search_len = RL_BUFSIZE + 1;
|
||||||
|
char search[search_len];
|
||||||
|
fseek(history_file, -search_len, SEEK_END); // go back 1025 characters from end of file
|
||||||
|
int count = fread(search, 1, search_len - 1, history_file); // try to read 1025 characters from file, returning count number of bytes
|
||||||
|
search[count] = '\0';
|
||||||
|
char *last_nlf = strrchr(search, '\n'); // locate last occurence of \n in a searching string
|
||||||
|
if (last_nlf == NULL) {
|
||||||
|
// no history
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (direction == 1) { // up
|
||||||
|
cmd_count++;
|
||||||
|
} else { // down
|
||||||
|
if (cmd_count == 0) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
cmd_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < cmd_count; i++) {
|
||||||
|
search[last_nlf - search] = '\0'; // terminate string earlier to find second last \n, search points to first char and last_nlf is last \n, difference is the index of \n
|
||||||
|
last_nlf = strrchr(search, '\n'); // call strrchr 2 times to get second last new line feed in search string as every life is new line feed
|
||||||
|
if ((last_nlf - search) == (strchr(search, '\n') - search)) {
|
||||||
|
// check if the first \n is the last \n we searching for, if yes it is first command
|
||||||
|
cmd_count--;
|
||||||
|
search[last_nlf - search] = '\0'; // terminate string earlier to find second last \n, search points to first char and last_nlf is last \n, difference is the index of \n
|
||||||
|
char *first_cmd = malloc(sizeof(char) * (last_nlf - search) + 1);
|
||||||
|
strcpy(first_cmd, search);
|
||||||
|
return first_cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(history_file);
|
||||||
|
return last_nlf + 1; // return the string from the new line feed
|
||||||
|
}
|
8
history.h
Normal file
8
history.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef HISTORY_H_
|
||||||
|
#define HISTORY_H_
|
||||||
|
|
||||||
|
void save_command_history(char *command);
|
||||||
|
void check_history_file();
|
||||||
|
char *read_command(int direction);
|
||||||
|
|
||||||
|
#endif
|
BIN
rush
Executable file
BIN
rush
Executable file
Binary file not shown.
362
rush.c
Normal file
362
rush.c
Normal file
|
@ -0,0 +1,362 @@
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "color.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "history.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Function Declarations for builtin shell commands:
|
||||||
|
*/
|
||||||
|
int rush_cd(char **args);
|
||||||
|
int help(char **args);
|
||||||
|
int rush_exit(char **args);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List of builtin commands, followed by their corresponding functions.
|
||||||
|
*/
|
||||||
|
char *builtin_str[] = {
|
||||||
|
"cd",
|
||||||
|
"help",
|
||||||
|
"exit"
|
||||||
|
};
|
||||||
|
|
||||||
|
int (*builtin_func[]) (char **) = {
|
||||||
|
&rush_cd,
|
||||||
|
&help,
|
||||||
|
&rush_exit
|
||||||
|
};
|
||||||
|
|
||||||
|
int rush_num_builtins() {
|
||||||
|
return sizeof(builtin_str) / sizeof(char *);
|
||||||
|
}
|
||||||
|
|
||||||
|
// change directory
|
||||||
|
int rush_cd(char **args) {
|
||||||
|
if (args[1] == NULL) {
|
||||||
|
char *home = getenv("HOME");
|
||||||
|
if (chdir(home) != 0) {
|
||||||
|
perror("rush");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (chdir(args[1]) != 0) {
|
||||||
|
perror("rush");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show help menu
|
||||||
|
int help(char **args) {
|
||||||
|
printf("rush v0.01-alpha\n");
|
||||||
|
printf("Built in commands:\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < rush_num_builtins(); i++) {
|
||||||
|
printf(" %s\n", builtin_str[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Use 'man' to read manual of programs\n");
|
||||||
|
printf("Licensed under GPL v3\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rush_exit(char **args) {
|
||||||
|
return 0; // exit prompting loop, which also the shell
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Launch a program and wait for it to terminate.
|
||||||
|
@param args Null terminated list of arguments (including program).
|
||||||
|
@return Always returns 1, to continue execution.
|
||||||
|
*/
|
||||||
|
int rush_launch(char **args) {
|
||||||
|
pid_t pid, wpid;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid == 0) {
|
||||||
|
// Child process
|
||||||
|
if (execvp(args[0], args) == -1) {
|
||||||
|
if (errno == ENOENT) {
|
||||||
|
fprintf(stderr, "rush: command not found: %s\n", args[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else if (pid < 0) {
|
||||||
|
perror("Cannot fork");
|
||||||
|
} else {
|
||||||
|
// Parent process
|
||||||
|
do {
|
||||||
|
wpid = waitpid(pid, &status, WUNTRACED);
|
||||||
|
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Execute shell built-in or launch program.
|
||||||
|
@param args Null terminated list of arguments.
|
||||||
|
@return 1 if the shell should continue running, 0 if it should terminate
|
||||||
|
*/
|
||||||
|
int rush_execute(char **args) {
|
||||||
|
if (args[0] == NULL) {
|
||||||
|
// An empty command was entered.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < rush_num_builtins(); i++) {
|
||||||
|
if (strcmp(args[0], builtin_str[i]) == 0) {
|
||||||
|
return (*builtin_func[i])(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rush_launch(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void change_terminal_attribute(int option) {
|
||||||
|
static struct termios oldt, newt;
|
||||||
|
tcgetattr(STDIN_FILENO, &oldt);
|
||||||
|
if (option) {
|
||||||
|
newt = oldt;
|
||||||
|
newt.c_lflag &= ~(ICANON | ECHO); // allows getchar without pressing enter key and echoing the character twice
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &newt); // set settings to stdin
|
||||||
|
} else {
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // restore to old settings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char **setup_path_variable() {
|
||||||
|
char *envpath = getenv("PATH");
|
||||||
|
char *path_cpy = malloc(sizeof(char) * (strlen(envpath) + 1));
|
||||||
|
char *path = malloc(sizeof(char) * (strlen(envpath) + 1));
|
||||||
|
strcpy(path_cpy, envpath);
|
||||||
|
strcpy(path, envpath);
|
||||||
|
int path_count = 0;
|
||||||
|
while (*path_cpy != '\0') {
|
||||||
|
// count number of : to count number of elements
|
||||||
|
if (*path_cpy == ':') {
|
||||||
|
path_count++;
|
||||||
|
}
|
||||||
|
path_cpy++;
|
||||||
|
}
|
||||||
|
path_count += 2; // adding one to be correct and one for terminator
|
||||||
|
char **paths = malloc(sizeof(char *) * path_count);
|
||||||
|
char *token = strtok(path, ":");
|
||||||
|
int counter = 0;
|
||||||
|
while (token != NULL) {
|
||||||
|
paths[counter] = token; // set element to the pointer of start of path
|
||||||
|
token = strtok(NULL, ":");
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
paths[counter] = NULL;
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool find_command(char **paths, char *command) {
|
||||||
|
if (strcmp(command, "") == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int counter = 0;
|
||||||
|
while (*paths != NULL) {
|
||||||
|
char current_path[PATH_MAX];
|
||||||
|
sprintf(current_path, "%s/%s", *paths, command);
|
||||||
|
if (access(current_path, X_OK) == 0) {
|
||||||
|
// command is executable
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
paths++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *rush_read_line(char **paths) {
|
||||||
|
int bufsize = RL_BUFSIZE;
|
||||||
|
int position = 0;
|
||||||
|
char *buffer = malloc(sizeof(char) * bufsize);
|
||||||
|
int c;
|
||||||
|
|
||||||
|
if (!buffer) {
|
||||||
|
fprintf(stderr, "rush: allocation error\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[0] = '\0';
|
||||||
|
while (1) {
|
||||||
|
c = getchar(); // read a character
|
||||||
|
int buf_len = strlen(buffer);
|
||||||
|
if (buf_len > 0) {
|
||||||
|
printf("\033[%dD", strlen(buffer)); // move cursor to the beginning
|
||||||
|
printf("\033[K"); // clear line to the right of cursor
|
||||||
|
}
|
||||||
|
// check each character user has input
|
||||||
|
// printf("%i\n", c);
|
||||||
|
switch (c) {
|
||||||
|
case EOF:
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 10: // enter/new line feed
|
||||||
|
buffer[buf_len] = '\0';
|
||||||
|
// clear all characters after the command
|
||||||
|
for (int start = buf_len + 1; buffer[start] != '\0'; start++) {
|
||||||
|
buffer[start] = '\0';
|
||||||
|
}
|
||||||
|
printf("%s\n", buffer); // print back the command in prompt
|
||||||
|
save_command_history(buffer);
|
||||||
|
return buffer;
|
||||||
|
case 127: // backspace
|
||||||
|
if (buf_len >= 1) {
|
||||||
|
buffer[buf_len - 1] = '\0'; // putting null character at last character to act as backspace
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 27: // arrow keys comes at three characters, 27, 91, then 65-68
|
||||||
|
if (getchar() == 91) {
|
||||||
|
int arrow_key = getchar();
|
||||||
|
if (arrow_key == 65) { // up
|
||||||
|
// read history file and fill prompt with latest command
|
||||||
|
char *last_command = read_command(1);
|
||||||
|
if (last_command != NULL) {
|
||||||
|
strcpy(buffer, last_command);
|
||||||
|
buf_len = strlen(buffer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else if (arrow_key == 66) { // down
|
||||||
|
char *last_command = read_command(0);
|
||||||
|
if (last_command != NULL) {
|
||||||
|
strcpy(buffer, last_command);
|
||||||
|
buf_len = strlen(buffer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else if (arrow_key == 67) { // right
|
||||||
|
break;
|
||||||
|
} else if (arrow_key == 68) { // left
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if (c > 31 && c < 127) {
|
||||||
|
buffer[buf_len] = c;
|
||||||
|
buffer[buf_len + 1] = '\0'; // make sure printf don't print random characters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char *cmd_part = strchr(buffer, ' ');
|
||||||
|
bool valid;
|
||||||
|
if (cmd_part != NULL) {
|
||||||
|
char *cmd = malloc(sizeof(char) * (cmd_part - buffer + 1));
|
||||||
|
for (int i = 0; i < (cmd_part - buffer); i++) {
|
||||||
|
cmd[i] = buffer[i];
|
||||||
|
}
|
||||||
|
cmd[cmd_part - buffer] = '\0';
|
||||||
|
valid = find_command(paths, cmd);
|
||||||
|
} else {
|
||||||
|
valid = find_command(paths, buffer);
|
||||||
|
}
|
||||||
|
if (valid) {
|
||||||
|
printf("\x1b[38;2;000;255;000m%s\x1b[0m", buffer); // print green as valid command
|
||||||
|
} else {
|
||||||
|
printf("\x1b[38;2;255;000;000m%s\x1b[0m", buffer); // print red as sinvalid command
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
// If we have exceeded the buffer, reallocate.
|
||||||
|
if ((buf_len + 1) >= bufsize) {
|
||||||
|
bufsize += RL_BUFSIZE;
|
||||||
|
buffer = realloc(buffer, bufsize);
|
||||||
|
if (!buffer) {
|
||||||
|
fprintf(stderr, "rush: allocation error\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// split line into arguments
|
||||||
|
char **rush_split_line(char *line) {
|
||||||
|
int bufsize = TOK_BUFSIZE, position = 0;
|
||||||
|
char **tokens = malloc(bufsize * sizeof(char*));
|
||||||
|
char *token;
|
||||||
|
|
||||||
|
if (!tokens) {
|
||||||
|
fprintf(stderr, "rush: Allocation error\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(line, TOK_DELIM);
|
||||||
|
while (token != NULL) {
|
||||||
|
tokens[position] = token;
|
||||||
|
position++;
|
||||||
|
|
||||||
|
if (position >= bufsize) {
|
||||||
|
bufsize += TOK_BUFSIZE;
|
||||||
|
tokens = realloc(tokens, bufsize * sizeof(char*));
|
||||||
|
if (!tokens) {
|
||||||
|
fprintf(stderr, "rush: Allocation error\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, TOK_DELIM);
|
||||||
|
}
|
||||||
|
tokens[position] = NULL;
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
// continously prompt for command and execute it
|
||||||
|
void command_loop(char **paths) {
|
||||||
|
char *line;
|
||||||
|
char **args;
|
||||||
|
int status = 1;
|
||||||
|
|
||||||
|
while (status) {
|
||||||
|
time_t t = time(NULL);
|
||||||
|
struct tm* current_time = localtime(&t); // get current time
|
||||||
|
char timestr[256];
|
||||||
|
char cwdstr[PATH_MAX];
|
||||||
|
if (strftime(timestr, sizeof(timestr), "[%H:%M:%S]", current_time) == 0) { // format time string
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (getcwd(cwdstr, sizeof(cwdstr)) == NULL) { // get current working directory
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char time[256];
|
||||||
|
strcpy(time, timestr);
|
||||||
|
color_text(time, lavender); // lavender colored time string
|
||||||
|
char *cwd = malloc(sizeof(char) * PATH_MAX);
|
||||||
|
sprintf(cwd, "[%s]", cwdstr);
|
||||||
|
color_text(cwd, pink); // pink colored current directory
|
||||||
|
char arrow[32] = "»";
|
||||||
|
color_text(arrow, blue);
|
||||||
|
printf("%s %s %s ", time, cwd, arrow);
|
||||||
|
|
||||||
|
|
||||||
|
line = rush_read_line(paths);
|
||||||
|
args = rush_split_line(line);
|
||||||
|
status = rush_execute(args);
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
free(args);
|
||||||
|
free(cwd);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
// setup
|
||||||
|
check_history_file();
|
||||||
|
char **paths = setup_path_variable();
|
||||||
|
change_terminal_attribute(1); // turn off echoing and disabling getchar requires pressing enter key to return
|
||||||
|
|
||||||
|
command_loop(paths);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
change_terminal_attribute(0); // change back to default settings
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
Loading…
Reference in a new issue