Skip to content
Snippets Groups Projects
Commit cff653b2 authored by Zsombor Szabo-Antalovszky's avatar Zsombor Szabo-Antalovszky
Browse files

Committing source code

parents
Branches
No related tags found
No related merge requests found
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "10.0.22621.0",
"compilerPath": "C:/msys64/ucrt64/bin/g++.exe",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "windows-msvc-x64"
}
],
"version": 4
}
\ No newline at end of file
nosh.cpp 0 → 100644
/**
* Copyright (c) 2025 Zsombor Szabó-Antalovszky
*
* -------------------------------------------------------------------------------------------------------------------
* Dear future programmer,
*
* When I started writing this, I was feeling pretty good about it, thinking I had everything
* figured out. But as it grew, I'm starting to think maybe only the universe knows how this
* thing really works.
*
* If, for some crazy reason, someone actually ends up using or expanding on this open-source code,
* I feel for you. If things break in ways I couldn't even predict (and they will),
* just go ahead and bump this counter up:
*
* total_hours_wasted_here = 254;
*
* -------------------------------------------------------------------------------------------------------------------
*
* Noémi Shell (nosh). An open-source Shell developed for Windows-based systems
*
* Handles shell operations, heavily inspired by bash and zsh.
*
* @author Zsombor Szabó-Antalovszky
* @author ChatGPT (a lot of help)
*
* Licensed under a modified MIT License. See the license on the Noémi Shell GitLab repo for details.
*/
#include <iostream>
#include <string> // Handling strings
#include <vector>
#include <windows.h> // For using the Windows API
#include <filesystem> // For file system operations
#include <fstream> // Reading/Creating files
#include <cstring> // String operations
#include <regex> // For grasp filtering
#define VERSION 0.3 //< Change version number here for the entire code
#define STRLEN 100 //< Max string length
char vault[STRLEN]; //< Storing custom info;
namespace fs = std::filesystem;
using namespace std;
// Declaring functions
void handle_pwd(const vector<string>& args);
bool is_builtin_command(const vector<string>& args);
void handle_noemi(const vector<string>& args);
void handle_list(const vector<string>& args);
void handle_cd(const vector<string>& args);
void handle_storage(const vector<string>& args);
void handle_read(const vector<string>& args, string filename);
void handle_grasp(const vector<string>& args);
void handle_tap(const vector<string>& args);
void handle_crush(const vector<string>& args);
void handle_mkdir(const vector<string>& args);
void handle_rn(const vector<string>& args);
/**
* The main code
*/
int main() {
cout << "Noemi Shell (nosh)\n";
cout << "Copyright (C) 2025 Zsombor Szabo-Antalovszky\n\n";
string command; // Storing command
while (true) {
cout << "nosh> ";
getline(cin, command);
// On 'exit' command
if (command == "exit"){
cout << "Exiting...\n";
break;
}
vector<string> args;
string temp;
bool in_quotes = false;
for (size_t i = 0; i < command.size(); ++i) {
char ch = command[i];
if (ch == '"') { // Toggle in_quotes state on encountering a quote
in_quotes = !in_quotes;
}
else if (ch == ' ' && !in_quotes) { // Treat space as separator only if not in quotes
if (!temp.empty()) {
args.push_back(temp);
temp.clear();
}
}
else {
temp += ch;
}
}
// Push the last argument if any
if (!temp.empty()) {
args.push_back(temp);
}
// Ignore empty commands
if (args.empty()) {
continue;
}
// Example: Handling unrecognized commands
if (!is_builtin_command(args)) {
cout << "Unrecognized command: ";
for (const auto& arg : args) {
cout << arg << " ";
}
cout << endl;
}
}
return 0; // Terminate program with success
}
/**
* Function for handling the pwd command
*
* @param args for the arguments
*/
/**
* Handling the 'pwd' command for printing the working directory
*
* @param args for arguments.
*/
void handle_pwd(const vector<string>& args){
if (args.size() > 1) {
cerr << "pwd: too many arguments/n"; // In case any arguments are found
return; // Exit early
}
char buffer[MAX_PATH]; // Buffer for path
// Gets the current directory
if (GetCurrentDirectoryA(MAX_PATH, buffer)) {
cout << buffer << endl;
}
}
/**
* Function for checking/handling builtin commands, and executing them accordingly
*
* @param args for the arguments
* @return bool true of false whether the command exists or not
*/
bool is_builtin_command(const vector<string>& args){
if (args[0] == "pwd") {
handle_pwd(args);
return true;
}
if (args[0] == "about") {
if (args.size() > 2){
cout << "about: too many arguments\n";
return true;
}
if (args.size() == 2) {
if (args[1] == "--version"){
cout << "v" << VERSION;
cout << "\n";
return true;
}
else{
cout << "unrecognized argument: " << args[1];
return true;
}
}
cout << "\nNoemi Shell v" << VERSION;
cout << "\n";
cout << "Copyright (C) 2025 Zsombor Szabo-Antalovszky \n" << endl;
return true;
}
if (args[0] == "clear") {
if (args.size() > 1) {
cout << "clear: too many arguments";
return true;
}
system("cls");
return true;
}
if (args[0] == "noemi"){
handle_noemi(args);
return true;
}
if (args[0] == "cd"){
handle_cd(args);
return true;
}
if (args[0] == "list") {
handle_list(args);
return true;
}
if (args[0] == "store") {
handle_storage(args);
return true;
}
if (args[0] == "read") {
handle_read(args, args[1]);
return true;
}
if (args[0] == "grasp"){
handle_grasp(args);
return true;
}
if (args[0] == "tap"){
handle_tap(args);
return true;
}
if (args[0] == "crush"){
handle_crush(args);
return true;
}
if (args[0] == "mkdir"){
handle_mkdir(args);
return true;
}
if (args[0] == "rn"){
handle_rn(args);
return true;
}
return false; // Return false if given command does not exist
}
/**
* Though the name sounds dirty, this is a very lovely function that draws a heart out of '#' characters.
* every time the user enters the command 'noemi'
*
* @param args for arguments
* @param time for adjusting smoothness of draw
*/
void handle_noemi(const vector<string>& args){
if (args.size() > 2){
cout << "Usage: noemi <delay argument> ";
return; // Exit early
}
int time = 60; // Default time 60;
// In case an argument follows the command
if (args.size() == 2){
const string option = args[1]; // Set the option variable to the first argument
if (option == "-l") time = 500; // 500 milliseconds between each line
else{
cout << "noemi: unrecognized argument " << args[1] << "\n";
return; // Exit early;
}
}
cout << " \n\t ####### #######\n";
Sleep(time);
cout << " ########### ###########\n";
Sleep(time);
cout << " ############### ###############\n";
Sleep(time);
cout << " #################################\n";
Sleep(time);
cout << " ###################################\n";
Sleep(time);
cout << " ###################################\n";
Sleep(time);
cout << " #################################\n";
Sleep(time);
cout << " ###############################\n";
Sleep(time);
cout << " ###########################\n";
Sleep(time);
cout << " #######################\n";
Sleep(time);
cout << " ###################\n";
Sleep(time);
cout << " ###############\n";
Sleep(time);
cout << " #######\n";
Sleep(time);
cout << " ###\n";
Sleep(time);
cout << " #\n\n";
}
/**
* Handling the 'list' command for listing files and directories.
*
* @param args for arguments.
*/
void handle_list(const vector<string>& args){
fs::path target_path = fs::current_path();
if (args.size() > 1) {
target_path = args[1]; // Target path is the first arguments
// Checks if directory exists
if (!fs::exists(target_path) || !fs::is_directory(target_path)) {
cerr << "list: " << args[1] << ": No such directory" << endl;
return; // Exit early
}
}
try {
// If directory, mark with [DIR]. If file, mark with [FILE]
for (const auto& entry : fs::directory_iterator(target_path)){
cout << (entry.is_directory() ? "[DIR] " : "[FILE] ");
cout << entry.path().filename().string() << endl;
}
} catch (const fs::filesystem_error e) {
// If there is an error reading directory
cerr << "list: Error reading directory: " << e.what() << endl;
}
}
/**
* Handling the 'cd' command for changing directories
*
* @param args for arguments.
*/
void handle_cd(const vector<string>& args) {
if (args.size() > 2) {
cout << "cd: too many arguments\n";
return; // Exit early
}
if (args.size() == 1) {
// No argument, go to home directory
const char* home_dir = getenv("USERPROFILE"); // Get home directory on Windows
if (home_dir) {
fs::path home_path = home_dir;
fs::current_path(home_path); // Change to home directory
cout << "Changed directory to: " << home_path << endl;
} else {
cout << "cd: Home directory not found.\n";
}
}
else if (args[1] == "..") {
// cd .., go up one directory level
fs::path current_path = fs::current_path();
fs::path parent_path = current_path.parent_path(); // Get the parent directory
fs::current_path(parent_path); // Change the current path
cout << "Changed directory to: " << parent_path << endl;
}
else {
// Try to change to the directory specified by the user
fs::path new_path = args[1];
if (fs::exists(new_path) && fs::is_directory(new_path)) {
fs::current_path(new_path);
cout << "Changed directory to: " << new_path << endl;
} else {
cout << "cd: " << new_path << ": No such directory\n";
}
}
}
/**
* Handling the 'read' command for reading text from text based files.
*
* @param args for arguments.
*/
void handle_read(const vector<string>& args, string filename) {
// If there is no argument after command
if (args.size() != 2) {
cout << "Usage: read <filename>\n";
return; // Exit early
}
// Open the file for reading
ifstream file(filename);
if (!file.is_open()) {
cerr << "read: unable to open file: " << filename << "\n";
return; // Exit early
}
// Read and display file contents
string line;
bool isEmpty = true;
while (getline(file, line)) {
cout << line << "\n";
isEmpty = false;
}
if (isEmpty) {
cout << "read: file is empty: " << filename << "\n";
}
file.close(); // CLosing the file
}
/**
* Handling the 'store' command for storing a string of maximum 100 characters during runtime.
*
* @param args for arguments.
*/
void handle_storage(const vector<string>& args) {
if (args.size() == 1) {
// Store new text in memory
cout << "Enter text to store in memory (MAX 100 characters): ";
cin.getline(vault, STRLEN); // Use getline to capture input
cout << "Storing: \"" << vault << "\" in memory.\n";
} else if (args.size() == 2 && args[1] == "get") {
// Retrieve stored text
if (strlen(vault) == 0) {
cout << "No text stored in memory.\n";
} else {
cout << "Stored text: \"" << vault << "\"\n";
}
} else if (args.size() == 2) {
// Handle unrecognized arguments
cout << "store: unrecognized argument: " << args[1] << "\n";
} else {
// Handle too many arguments
cout << "store: too many arguments\n";
}
}
/**
* Handling the 'grasp' command for filtering results
*
* @param args for arguments.
*/
void handle_grasp(const vector<string>& args){
if (args.size() != 4){
cout << "Usage: grasp <type> <directory> <pattern>\n";
return; // Exits early
}
const string type = args[1];
const string dirPath = args[2];
const string pattern = args[3];
// IF the type argument is invalid
if (args[1] != "-d" && args[1] != "-f"){
cout << "grasp: invalid argument for type";
return; // Exit early
}
if (args[1] == "-d") {
if (!filesystem::exists(dirPath)) {
cout << "grasp: the directory " << dirPath << " does not exist.\n";
return; // Exit early
}
if (!filesystem::is_directory(dirPath)) {
cout << "grasp: " << dirPath << " is not a directory.\n";
return; // Exit early
}
// Iterate through directory contents
for (const auto& entry : filesystem::directory_iterator(dirPath)) {
const string name = entry.path().filename().string(); // Get the name of the entry
// Check if it's a directory and matches the pattern
if (entry.is_directory() && name.find(pattern) != string::npos) {
cout << name << endl; // Print matching directory name
}
}
}
if (type == "-f"){
// Check if the directory exists
if (!filesystem::exists(dirPath)) {
cout << "grasp: the directory " << dirPath << " does not exist.\n";
return; // Exit early
}
// Ensure it's a directory
if (!filesystem::is_directory(dirPath)) {
cout << "grasp: " << dirPath << " is not a directory.\n";
return; // Exit early
}
// Iterate through directory contents
for (const auto& entry : filesystem::directory_iterator(dirPath)) {
const string name = entry.path().filename().string();
// Check if it's a file and matches the pattern
if (entry.is_regular_file() && name.find(pattern) != string::npos) {
cout << name << endl; // Print matching file name
}
}
}
}
/**
* Handling the 'tap' command for creating files.
*
* @param args for arguments.
*/
void handle_tap(const vector<string>& args){
if (args.size() != 2){
cout << "Usage: tap <filename>\n";
return;
}
const string filename = args[1];
ofstream file(args[1]);
if (!file) {
cerr << "tap: Unable to create file: " << filename;
return;
}
file.close();
}
/**
* Handling the 'crush' command for removing files and directories.
*
* @param args for arguments.
*/
void handle_crush(const vector<string>& args) {
if (args.size() != 3){
cout << "usage: crush <type> <filename>\n";
return;
}
const string type = args[1];
const string filename = args[2];
if (type == "-f"){
if (filesystem::exists(filename)){
filesystem::remove(filename);
}
else{
cout << "crush: File does not exist: " << filename << endl;
}
}
if (type == "-d") {
if (std::filesystem::is_directory(filename)) {
char prompt;
cout << "Are you sure you want to remove: " << filename << "?\n";
cout << "There is NO UNDO! \n";
cout << "Choose Y/N: ";
cin >> prompt;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
switch (toupper(prompt)) {
case 'Y':
// Pass the directory path to remove_all
std::filesystem::remove_all(filename); // This removes the directory and all its contents
cout << "Directory and its contents have been removed: \n" << filename << endl;
break;
default:
cout << "Operation cancelled.\n";
break;
}
} else {
cout << "The specified path is not a valid directory: " << filename << endl;
}
}
}
/**
* Handling the 'mkdir' command for creating directories.
*
* @param args for arguments.
*/
void handle_mkdir(const vector<string>& args) {
if (args.size() != 2){
cout << "Usage: mkdir <directory_name>\n";
return;
}
const string dirName = args[1];
if (fs::exists(dirName)) {
cout << "Directory already exists: " << dirName << endl;
return;
}
// Create the directory
if (!fs::create_directory(dirName)) {
cout << "Failed to create directory: " << dirName << endl;
}
}
/**
* Handling the 'rn' command for renaming files and directories.
*
* @param args for arguments.
*/
void handle_rn(const vector<string>& args){
if (args.size() != 3){
cout << "Usage: rn <filename> <rename>\n";
return;
}
const string filename = args[1];
const string rename = args[2];
try
{
filesystem::rename(filename, rename);
}
catch(const std::exception& e)
{
cerr << "Error: " << e.what() << '\n';
}
}
\ No newline at end of file
nosh.exe 0 → 100644
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment