New repo setup
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.o
|
||||
*.idea
|
||||
shell
|
||||
init
|
||||
44
Makefile
Normal file
44
Makefile
Normal file
@@ -0,0 +1,44 @@
|
||||
CC = aarch64-none-elf-gcc
|
||||
CXX = aarch64-none-elf-g++
|
||||
AS = aarch64-none-elf-as
|
||||
AR = aarch64-none-elf-ar
|
||||
prefix:=$(HOME)/.cros/root
|
||||
|
||||
COMMANDS_SRCS = $(wildcard src/commands/*.cpp)
|
||||
SHELL_OBJS = src/shell.o src/utility.o src/command.o
|
||||
INIT_OBJ = init.o
|
||||
|
||||
COMMANDS_TARGETS = $(COMMANDS_SRCS:src/commands/%.cpp=bin/%)
|
||||
SHELL_TARGET = shell
|
||||
INIT_TARGET = init
|
||||
|
||||
CXXFLAGS = -I$(prefix)/include -Isrc -Isrc/commands -ffreestanding -nostdlib -fpermissive -fno-exceptions -fno-rtti -Wall -Wextra -ggdb -O0
|
||||
LDFLAGS = -L$(prefix)/lib -nostdlib
|
||||
LIBS = -lc -lsyscall
|
||||
|
||||
.PHONY: all
|
||||
all: $(COMMANDS_TARGETS) $(SHELL_TARGET) $(INIT_TARGET)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf ./bin $(SHELL_TARGET) $(INIT_TARGET) $(SHELL_OBJS) $(INIT_OBJ) src/commands/*.o
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
mkdir -p $(prefix)/bin
|
||||
cp -a bin/. $(prefix)/bin
|
||||
cp $(SHELL_TARGET) $(prefix)/bin
|
||||
cp $(INIT_TARGET) $(prefix)/bin
|
||||
|
||||
# Compiling individual command files
|
||||
bin/%: src/commands/%.o
|
||||
@mkdir -p bin
|
||||
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o $@ $< $(LIBS)
|
||||
|
||||
# Compiling shell.cpp
|
||||
$(SHELL_TARGET): $(SHELL_OBJS)
|
||||
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
# Compiling shell INIT
|
||||
$(INIT_TARGET): $(INIT_OBJ)
|
||||
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o $@ $^ $(LIBS)
|
||||
25
README.md
Normal file
25
README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# SHELL COMMAND DOCUMENTATION:
|
||||
1. `$ help` provides a quick reference for available commands.
|
||||
3. `$ echo <(opt) args>` Echos back the provided argument(s). Will include double quote.
|
||||
4. `$ joke` provides a tasteful joke.
|
||||
5. `$ ls <(opt) arg>` Provides the files and directories at the provided location. Prints files and directories in current directory if no arg given.
|
||||
6. `$ cd <arg>` BUILT-IN: Changes current directory to provided file location.
|
||||
7. `$ pwd` BUILT-IN: Provides an exact location of the current directory.
|
||||
|
||||
---
|
||||
# ./commands/*
|
||||
|
||||
Commands created as separate cpp files. Compiled into `./bin` during `make`.
|
||||
|
||||
pwd and cd are built-ins.
|
||||
|
||||
---
|
||||
# Compiling and Running
|
||||
|
||||
* `make`
|
||||
* `make install prefix=PATH_TO_INSTALL_DIRECTORY`
|
||||
|
||||
* Don't forget `make clean`
|
||||
|
||||
Authored by Connor
|
||||
echo.cpp authored by Kyle
|
||||
89
init.cpp
Normal file
89
init.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
char **envp_global;
|
||||
int pipefd_stdout[2];
|
||||
int pipefd_stdin[2];
|
||||
|
||||
void shellThread(void *ptr)
|
||||
{
|
||||
fddup(pipefd_stdout[1], 1);
|
||||
fddup(pipefd_stdin[0], 0);
|
||||
char *args[] = {"/bin/shell", NULL};
|
||||
// exec("/bin/shell", args, envp);
|
||||
execve("shell", args, envp_global);
|
||||
terminate();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
const int stackSize = 1024;
|
||||
printf("%s: Starting shell\n", argv[0]);
|
||||
void *stack = malloc(stackSize);
|
||||
envp_global = envp;
|
||||
|
||||
printf("%s: Creating pipes\n", argv[0]);
|
||||
create_pipe(pipefd_stdout);
|
||||
create_pipe(pipefd_stdin);
|
||||
|
||||
printf("%s: Spawning new thread\n", argv[0]);
|
||||
clone(shellThread, stack + stackSize, nullptr, 0);
|
||||
|
||||
printf("%s: Entering I/O loop\n", argv[0]);
|
||||
char line[1024];
|
||||
char buffer[1024];
|
||||
int pos = 0;
|
||||
while (true)
|
||||
{
|
||||
// printf("init: I/O loop\n");
|
||||
int status = read(0, &buffer[pos], 1);
|
||||
// printf("init: Read status: %d\n", status);
|
||||
while (status > 0)
|
||||
{
|
||||
char str[2];
|
||||
str[0] = buffer[pos];
|
||||
str[1] = '\0';
|
||||
printf("%s", str);
|
||||
if (str[0] == '\r')
|
||||
{
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
pos += status;
|
||||
if (buffer[pos - 1] == '\r')
|
||||
{
|
||||
buffer[pos - 1] = '\n';
|
||||
buffer[pos] = '\0';
|
||||
fprintf(&pipefd_stdin[1], "%s", buffer);
|
||||
pos = 0;
|
||||
}
|
||||
else if (pos == 1023)
|
||||
{
|
||||
buffer[pos] = '\0';
|
||||
fprintf(&pipefd_stdin[1], "%s", buffer);
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
status = read(0, &buffer[pos], 1);
|
||||
}
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("init: Error reading from UART.\n");
|
||||
}
|
||||
|
||||
status = read(pipefd_stdout[0], line, 1023);
|
||||
// printf("init: Read2 status: %d\n", status);
|
||||
if (status > 0)
|
||||
{
|
||||
line[status] = '\0';
|
||||
printf("%s", line);
|
||||
}
|
||||
|
||||
yield();
|
||||
// printk("hi");
|
||||
}
|
||||
}
|
||||
164
src/command.cpp
Normal file
164
src/command.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
#include "command.h"
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "utility.h"
|
||||
#include <sys/syscall.h>
|
||||
|
||||
void spawn_command(char **args)
|
||||
{
|
||||
execvp(args[0], args);
|
||||
terminate();
|
||||
}
|
||||
|
||||
int Command::parse(std::string input)
|
||||
{
|
||||
// if input has \n appended to the end, remove it
|
||||
if (input[input.size() - 1] == '\n')
|
||||
{
|
||||
input = input.substr(0, input.size() - 1);
|
||||
}
|
||||
|
||||
std::string pipe_delim = "|";
|
||||
std::vector<std::string> parsed_input = split_string(input, pipe_delim);
|
||||
|
||||
if (Command::setup_command(parsed_input) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Command::run()
|
||||
{
|
||||
int i, j, pid;
|
||||
int num_instructions = instructions.size();
|
||||
|
||||
// If there is no pipe, just fork and execute the first command
|
||||
if (num_instructions == 1)
|
||||
{
|
||||
|
||||
// Check for built-in commands
|
||||
if (instructions[0][0] == "cd")
|
||||
{
|
||||
if (instructions[0].size() > 1)
|
||||
{
|
||||
return cd(instructions[0][1].c_str());
|
||||
}
|
||||
return cd("/");
|
||||
}
|
||||
else if (instructions[0][0] == "clear")
|
||||
{
|
||||
clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// No built-ins, execute elsewhere
|
||||
exec_instruction(instructions[0]);
|
||||
wait(NULL);
|
||||
return 0;
|
||||
}
|
||||
//////////////////////////////////
|
||||
|
||||
// Piping logic:
|
||||
// Initialize file descriptors for some piping
|
||||
int fd[num_instructions][2];
|
||||
|
||||
// Init the pipes
|
||||
int result = -1;
|
||||
for (i = 0; i < num_instructions; i++)
|
||||
{
|
||||
pipe(fd[i]);
|
||||
}
|
||||
|
||||
// Fork every instruction
|
||||
for (i = 0; i < num_instructions; i++)
|
||||
{
|
||||
pid = fork();
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
|
||||
// If this is not the first instruction
|
||||
if (i > 0)
|
||||
{
|
||||
|
||||
if (fd[i - 1][0] != 0)
|
||||
{
|
||||
dup2(fd[i - 1][0], 0);
|
||||
}
|
||||
}
|
||||
|
||||
// If this is not the last instruction
|
||||
if (i < num_instructions - 1)
|
||||
{
|
||||
if (fd[i][1] != 1)
|
||||
{
|
||||
dup2(fd[i][1], 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Close all descriptors
|
||||
for (j = 0; j < num_instructions; j++)
|
||||
{
|
||||
close(fd[j][0]);
|
||||
close(fd[j][1]);
|
||||
}
|
||||
|
||||
// Execute instruction
|
||||
exec_instruction(instructions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Close parent file descriptors
|
||||
for (i = 0; i < num_instructions; i++)
|
||||
{
|
||||
close(fd[i][0]);
|
||||
close(fd[i][1]);
|
||||
}
|
||||
|
||||
// Wait for all processes to finish
|
||||
for (int i = 0; i < num_instructions; i++)
|
||||
{
|
||||
wait(NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Command::setup_command(std::vector<std::string> &parsed_input)
|
||||
{
|
||||
std::string space_delim = " ";
|
||||
while (!parsed_input.empty())
|
||||
{
|
||||
std::string input = parsed_input.front();
|
||||
std::vector<std::string> instruction = split_string(input, space_delim);
|
||||
// terminate setup if input error
|
||||
if (instruction.empty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
instructions.push_back(instruction);
|
||||
parsed_input.remove(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Command::exec_instruction(std::vector<std::string> &instruction)
|
||||
{
|
||||
int num_args = instruction.size();
|
||||
char **arg = new char *[num_args + 1];
|
||||
for (size_t i = 0; i < num_args; i++)
|
||||
{
|
||||
arg[i] = new char[instruction[i].size() + 1];
|
||||
strcpy(arg[i], instruction[i].c_str());
|
||||
}
|
||||
arg[num_args] = nullptr;
|
||||
void *stack = malloc(1024);
|
||||
clone(spawn_command, stack + 1024, (void *)arg, 0);
|
||||
return 0;
|
||||
}
|
||||
50
src/command.h
Normal file
50
src/command.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef _COMMAND_H_
|
||||
#define _COMMAND_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* The entire line parsed is a "Command"
|
||||
* Each process with arguments included are an "Instruction"
|
||||
* The Command class stores each instruction as a vector and will pipe between
|
||||
* each instruction in the vector.
|
||||
*/
|
||||
class Command
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse each input by the pipe deliminator.
|
||||
* Setup the command with each parsed input.
|
||||
* @return 0 if successful
|
||||
* @return not 0 otherwise
|
||||
*/
|
||||
int parse(std::string command);
|
||||
|
||||
/**
|
||||
* Fork and exec the command.
|
||||
* Pipe to the next command if applicable.
|
||||
*/
|
||||
int run();
|
||||
|
||||
private:
|
||||
std::vector<std::vector<std::string>> instructions;
|
||||
|
||||
/**
|
||||
* Loops through every parsed input in a vector
|
||||
* Separates each segment o f a command by spaces
|
||||
* Embeds each segment of a command as an "instruction"
|
||||
* Each "instruction" is added to a vector called "instructions"
|
||||
* @param parsed_input a vector of commands separated by a vertical pipe "|"
|
||||
*/
|
||||
int setup_command(std::vector<std::string> &instructions);
|
||||
|
||||
/**
|
||||
* Executes the command
|
||||
* @param curr_command
|
||||
* @return
|
||||
*/
|
||||
int exec_instruction(std::vector<std::string> &instruction);
|
||||
};
|
||||
|
||||
#endif // !_COMMAND_H_
|
||||
66
src/commands/cp.cpp
Normal file
66
src/commands/cp.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// Created by connor on 2/12/24.
|
||||
//
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void cp(char* src_file_name, char* dest_file_name, bool overwrite) {
|
||||
FILE* src_file = fopen(src_file_name, "r");
|
||||
if (src_file == NULL) {
|
||||
fprintf(stderr, "Error opening src file: %s\n", src_file_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
FILE* dest_file = fopen(dest_file_name, "r");
|
||||
if (dest_file != NULL) {
|
||||
fclose(dest_file);
|
||||
if (!overwrite) {
|
||||
fclose(src_file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dest_file = fopen(dest_file_name, "w");
|
||||
if (dest_file == NULL) {
|
||||
fprintf(stderr, "Error opening dest file: %s\n", dest_file_name);
|
||||
fclose(src_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int ch;
|
||||
while ((ch = fgetc(src_file)) != EOF) {
|
||||
fputc(ch, dest_file);
|
||||
}
|
||||
|
||||
fclose(src_file);
|
||||
fclose(dest_file);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 3) {
|
||||
printf("Usage: cp <flags> <src file> <dest file1> <dest file2> ...\n");
|
||||
} else {
|
||||
int i = 1;
|
||||
char* flags = argv[1];
|
||||
int size = sizeof(flags);
|
||||
bool overwrite = false;
|
||||
if (flags[0] == '-') {
|
||||
i++;
|
||||
for (int j = 1; j < size; j++) {
|
||||
switch (flags[j]) {
|
||||
case 'o':
|
||||
overwrite = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = i + 1; j < argc; j++)
|
||||
cp(argv[i], argv[j], overwrite);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
20
src/commands/echo.cpp
Normal file
20
src/commands/echo.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Created by connor on 2/7/24.
|
||||
// functions similarly to linux ls
|
||||
//
|
||||
#include <stdio.h>
|
||||
|
||||
void echo(int argc, char* argv[]) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
printf("%s ", argv[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 2)
|
||||
printf("Usage: echo <prompt>\n");
|
||||
else
|
||||
echo(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
23
src/commands/help.cpp
Normal file
23
src/commands/help.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by connor on 2/12/24.
|
||||
//
|
||||
//
|
||||
#include <stdio.h>
|
||||
int main() {
|
||||
printf("Commands:\n");
|
||||
printf(" joke\n");
|
||||
printf(" echo <prompt>\n");
|
||||
printf(" ls <directory>\n");
|
||||
printf(" cd <path>\n");
|
||||
printf(" pwd\n");
|
||||
printf(" search <flags> <token> <file1> <file2> ...\n");
|
||||
printf(" -v: verbose\n");
|
||||
printf(" wc <flags> <file1> <file2> ...\n");
|
||||
printf(" -b: byte count\n");
|
||||
printf(" -c: character count\n");
|
||||
printf(" -w: word count\n");
|
||||
printf(" -l: line count\n");
|
||||
printf(" cp <flags> <src file> <dest file1> <dest file2> ...\n");
|
||||
printf(" -o: overwrite file\n");
|
||||
return 0;
|
||||
}
|
||||
35
src/commands/joke.cpp
Normal file
35
src/commands/joke.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Created by connor on 2/7/24.
|
||||
* 16 of the classiest jokes.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void joke() {
|
||||
const char* jokes[] = {
|
||||
"What do you call a factory that makes okay products? \nA satisfactory.",
|
||||
"What did one wall say to the other? \nI'll meet you at the corner.",
|
||||
"What did the zero say to the eight? \nThat belt looks good on you.",
|
||||
"If my wife thinks I'm obsessed with programming, she's crazy. \nendif.",
|
||||
"Hey girl, are you an object-oriented programming language?\nBecause you've got class.",
|
||||
"How many lightbulbs does it take to change a programmer? \nI don't know, but it sounds like somebody learned about dependency inversion.",
|
||||
"[\"Hip\",\"Hip\"]\nHip Hip Array!",
|
||||
"Why do programmers prefer dark mode?\nBecause the light attracts bugs!",
|
||||
"Why don't scientists trust atoms?\nBecause they make up everything!",
|
||||
"Why do Java developers wear glasses?\nBecause they don't see sharp!",
|
||||
"Why did the programmer quit his job?\nHe didn't get arrays!",
|
||||
"Why did the scarecrow win an award?\nBecause he was outstanding in his field!",
|
||||
"I told my wife she was drawing her eyebrows too high.\nShe looked surprised!",
|
||||
"I asked the librarian if the library had any books on paranoia.\nShe whispered, 'They're right behind you.'",
|
||||
"I used to play piano by ear. \nNow I use my hands and fingers.",
|
||||
"I told my wife she should embrace her mistakes.\nShe gave me a hug."};
|
||||
|
||||
int joke_index = rand() % 16;
|
||||
printf("%s\n", jokes[joke_index]);
|
||||
}
|
||||
|
||||
int main() {
|
||||
joke();
|
||||
return 0;
|
||||
}
|
||||
38
src/commands/ls.cpp
Normal file
38
src/commands/ls.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Created by connor on 2/7/24.
|
||||
// functions similarly to linux ls
|
||||
//
|
||||
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void ls(char* dir_path) {
|
||||
DIR* dir = opendir(dir_path);
|
||||
if (dir == NULL) {
|
||||
fprintf(stderr, "Error opening directory: %s\n", dir_path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
|
||||
printf("%s\n", entry->d_name);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc == 1) {
|
||||
char dir[100];
|
||||
getcwd(dir, sizeof(dir));
|
||||
ls(dir);
|
||||
} else {
|
||||
for (int i = 1; i < argc; i++)
|
||||
ls(argv[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
18
src/commands/mkdir.cpp
Normal file
18
src/commands/mkdir.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Created by connor on 2/12/24.
|
||||
//
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
void mkdir_func(char* dir_path) {
|
||||
mkdir(dir_path);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc > 1) {
|
||||
mkdir_func(argv[2]);
|
||||
}
|
||||
printf("mkdir not implemented.");
|
||||
return 0;
|
||||
}
|
||||
9
src/commands/mv.cpp
Normal file
9
src/commands/mv.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
//
|
||||
// Created by connor on 2/12/24.
|
||||
//
|
||||
//
|
||||
#include <stdio.h>
|
||||
int main() {
|
||||
printf("mv not implemented.");
|
||||
return 0;
|
||||
}
|
||||
18
src/commands/pwd.cpp
Normal file
18
src/commands/pwd.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Created by connor on 2/12/24.
|
||||
//
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int pwd() {
|
||||
char cwd[128];
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
return printf("%s\n", cwd);
|
||||
}
|
||||
|
||||
int main() {
|
||||
pwd();
|
||||
|
||||
return 0;
|
||||
}
|
||||
9
src/commands/rm.cpp
Normal file
9
src/commands/rm.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
//
|
||||
// Created by connor on 2/12/24.
|
||||
//
|
||||
//
|
||||
#include <stdio.h>
|
||||
int main() {
|
||||
printf("rm not implemented.");
|
||||
return 0;
|
||||
}
|
||||
78
src/commands/search.cpp
Normal file
78
src/commands/search.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// Created by connor on 2/12/24.
|
||||
//
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void search(char *token, char *file_name, bool verbose)
|
||||
{
|
||||
FILE *file;
|
||||
file = fopen(file_name, "r");
|
||||
if (file == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error opening file: %s\n", file_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char line[1024]; // assuming max line length is 1024 chars
|
||||
int line_number = 1;
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
printf("%s:\n", file_name);
|
||||
printf("%s occurences:\n", token);
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), file) != NULL)
|
||||
{
|
||||
char *occurrence = strstr(line, token);
|
||||
while (occurrence != NULL)
|
||||
{
|
||||
if (verbose)
|
||||
printf(" line: %d, index: %d %s", line_number, occurrence - line + 1, line);
|
||||
else
|
||||
printf("%d %d %s", line_number, occurrence - line + 1, line);
|
||||
occurrence = strstr(occurrence + 1, token);
|
||||
}
|
||||
line_number++;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc <= 2)
|
||||
{
|
||||
printf("Usage: search <flags> <token> <file1> <file2> ...\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = 2;
|
||||
char *flags = argv[1];
|
||||
int size = sizeof(flags);
|
||||
bool verbose = false;
|
||||
if (flags[0] == '-')
|
||||
{
|
||||
i++;
|
||||
for (int j = 1; j < size; j++)
|
||||
{
|
||||
switch (flags[j])
|
||||
{
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *token = argv[i - 1];
|
||||
for (; i < argc; i++)
|
||||
search(token, argv[i], verbose);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
127
src/commands/wc.cpp
Normal file
127
src/commands/wc.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// Created by connor on 2/12/24.
|
||||
//
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void wc(char *file_name, bool show_chars, bool show_bytes, bool show_words, bool show_lines)
|
||||
{
|
||||
FILE *file;
|
||||
file = fopen(file_name, "r");
|
||||
if (file == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error opening file: %s\n", file_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int lines = 1;
|
||||
int words = 0;
|
||||
int characters = 0;
|
||||
int bytes = 0;
|
||||
|
||||
if (show_chars || show_words || show_lines)
|
||||
{
|
||||
int in_word = 0;
|
||||
int ch = 0;
|
||||
|
||||
while ((ch = fgetc(file)) != EOF)
|
||||
{
|
||||
characters++;
|
||||
|
||||
if (ch == '\n')
|
||||
{
|
||||
lines++;
|
||||
}
|
||||
|
||||
if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f')
|
||||
{
|
||||
in_word = 0;
|
||||
}
|
||||
else if (in_word == 0)
|
||||
{
|
||||
in_word = 1;
|
||||
words++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (show_bytes)
|
||||
{
|
||||
if (fseek(file, 0, SEEK_END) != 0)
|
||||
{
|
||||
fprintf(stderr, "Error reading file: %s\n", file_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bytes = ftell(file);
|
||||
if (bytes == -1)
|
||||
{
|
||||
fprintf(stderr, "Error reading file: %s\n", file_name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
printf("%s:\n", file_name);
|
||||
if (show_bytes)
|
||||
printf(" bytes: %d\n", bytes);
|
||||
if (show_chars)
|
||||
printf(" characters: %d\n", characters);
|
||||
if (show_words)
|
||||
printf(" words: %d\n", words);
|
||||
if (show_lines)
|
||||
printf(" lines: %d\n", lines);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc <= 1)
|
||||
{
|
||||
printf("Usage: wc <flags> <file1> <file2> ...\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = 1;
|
||||
char *flags = argv[1];
|
||||
int size = sizeof(flags);
|
||||
bool show_chars = false;
|
||||
bool show_bytes = false;
|
||||
bool show_words = false;
|
||||
bool show_lines = false;
|
||||
if (flags[0] == '-')
|
||||
{
|
||||
i++;
|
||||
for (int j = 1; j < size; j++)
|
||||
{
|
||||
switch (flags[j])
|
||||
{
|
||||
case 'c':
|
||||
show_chars = true;
|
||||
break;
|
||||
case 'b':
|
||||
show_bytes = true;
|
||||
break;
|
||||
case 'w':
|
||||
show_words = true;
|
||||
break;
|
||||
case 'l':
|
||||
show_lines = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < argc; i++)
|
||||
{
|
||||
if (!show_chars && !show_bytes && !show_words && !show_lines)
|
||||
wc(argv[i], show_chars, show_bytes, true, show_lines);
|
||||
else
|
||||
wc(argv[i], show_chars, show_bytes, show_words, show_lines);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
74
src/shell.cpp
Normal file
74
src/shell.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Created by connor on 2/20/24.
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "command.h"
|
||||
#include "utility.h"
|
||||
#include <string>
|
||||
|
||||
#define INPUT_MAX 128
|
||||
#define HISTORY_MAX 10
|
||||
char HISTORY[HISTORY_MAX];
|
||||
|
||||
/**
|
||||
* Main loop for the terminal.
|
||||
* 1. Print the prompt including current fs location
|
||||
* 2. Get the userinput using fgets into input
|
||||
* 3. Convert char input into string input_str
|
||||
* 4. Create a new command object and parse the input into the object.
|
||||
* 5. Call the run() method on the command object if parsed successfully.
|
||||
* 6. Flush input
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
|
||||
// stuff from utility.h
|
||||
clear();
|
||||
PRINT_BANNER();
|
||||
//
|
||||
|
||||
while (1)
|
||||
{
|
||||
// user input and file system location
|
||||
int parse_status, run_status;
|
||||
char input[INPUT_MAX], cwd[128];
|
||||
|
||||
// get the current fs location and print a prompt
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
printf("\033[32m%s\033[0m$ ", cwd);
|
||||
if (!fgets(input, sizeof(input), stdin)) {
|
||||
// if something is wrong with stdin, we're screwed.
|
||||
continue;
|
||||
}
|
||||
|
||||
// get user input as a string and check for empty input
|
||||
std::string input_str(input);
|
||||
|
||||
// BLANK INPUT
|
||||
if (input_str.size() <= 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// printf("%s", input);
|
||||
|
||||
// parse the new command
|
||||
Command command;
|
||||
parse_status = command.parse(input_str);
|
||||
if (parse_status < 0) {
|
||||
printf("\033[1;31mUnrecognized command..\n\033[0m");
|
||||
continue;
|
||||
}
|
||||
|
||||
run_status = command.run();
|
||||
if (run_status < 0) {
|
||||
printf("\033[1;31mUnexpected failure running command..\n\033[0m");
|
||||
}
|
||||
|
||||
// flush input
|
||||
// scanf("%*[^\n]%*1[\n]");
|
||||
// getchar();
|
||||
}
|
||||
}
|
||||
51
src/utility.cpp
Normal file
51
src/utility.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// Created by connor on 2/21/24.
|
||||
//
|
||||
#include "utility.h"
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
std::vector<std::string> split_string(std::string &str,
|
||||
const std::string &delimiter) {
|
||||
size_t pos = 0;
|
||||
std::vector<std::string> parsed_input;
|
||||
if (str.find(delimiter) != std::string::npos) {
|
||||
while ((pos = str.find(delimiter)) != std::string::npos) {
|
||||
std::string token = str.substr(0, pos);
|
||||
if (token.size() > 0) {
|
||||
parsed_input.push_back(token);
|
||||
}
|
||||
str.erase(0, pos + delimiter.size());
|
||||
}
|
||||
}
|
||||
if (str.size() > 0)
|
||||
parsed_input.push_back(str);
|
||||
return parsed_input;
|
||||
}
|
||||
|
||||
int cd(const char *str) {
|
||||
if (chdir(str) != 0) {
|
||||
printf("Unable to find path.\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PRINT_BANNER() {
|
||||
printf("\033[32m________ ________ ________ ________\n\033[0m");
|
||||
printf("\033[32m|\\ ____\\|\\ __ \\|\\ __ \\|\\ ____\\\n\033[0m");
|
||||
printf("\033[32m\\ \\ \\___|\\ \\ \\|\\ \\ \\ \\|\\ \\ \\ \\___|_\n\033[0m");
|
||||
printf("\033[32m \\ \\ \\ \\ \\ _ _\\ \\ \\\\\\ \\ \\_____ \\\n\033[0m");
|
||||
printf("\033[32m \\ \\ \\____\\ \\ \\\\ \\\\ \\ \\\\\\ \\|____|\\ \\\n\033[0m");
|
||||
printf("\033[32m \\ \\_______\\ \\__\\\\ _\\\\ \\_______\\____\\_\\ \\\n\033[0m");
|
||||
printf("\033[32m \\|_______|\\|__|\\|__|\\|_______|\\_________\\\n\033[0m");
|
||||
printf("\033[32m \\|_________|\n\033[0m");
|
||||
printf("\033[32m \"Powered by terminal gremlins and questionable memory accessing.\"\n\n\033[0m");
|
||||
|
||||
printf("Input a command or use '\033[34mhelp\033[0m' for some ideas\n");
|
||||
}
|
||||
|
||||
void clear() {
|
||||
printf("\033[H\033[J");
|
||||
}
|
||||
32
src/utility.h
Normal file
32
src/utility.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Created by connor on 2/21/24.
|
||||
//
|
||||
|
||||
#ifndef EOS_UTILITY_H
|
||||
#define EOS_UTILITY_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
* split up a string into a vector of strings based on the given delimiter
|
||||
*/
|
||||
std::vector<std::string> split_string(std::string &str,
|
||||
const std::string &delimiter);
|
||||
|
||||
/*
|
||||
* change directory
|
||||
*/
|
||||
int cd(const char *str);
|
||||
|
||||
/*
|
||||
* Prints a banner.
|
||||
*/
|
||||
void PRINT_BANNER();
|
||||
|
||||
/*
|
||||
* Clears the screen.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
#endif // EOS_UTILITY_H
|
||||
Reference in New Issue
Block a user