Ahoy, fellow code sailors! Welcome to my GitHub harbor, where the epic tales of the 42 Minishell project unfold. Dive into the coding seas, but remember, face the challenges alone before setting sail with my solutions, savvy?
Minishell is a project that invites you to a symphony of shell scripting. It's like conducting an orchestra of commands—a true coding performance! 🎻🔍
Simply chant this command, and you're on board the ship:
git clone https://github.com/RPDJF/42-minishell.git
Just a few magic spells to summon your Minishell masterpiece:
make
: For a regular enchantment. Compile that code, and you're ready for the grand shell performance!make bonus
: Feeling adventurous? Add the bonus ingredients for an extra shell crescendo.make clean
: Clear away the traces of your enchantment. A tidy workspace is a powerful workspace.make fclean
: Need a clean slate? This erases all enchantments, leaving nothing behind.make debug
: Unleash the debug sorcery using gdb. Warning: It leaves behind extra mystical artifacts not handled by make fclean
.Navigate this mystical realm with these commands, and may your Minishell journey be legendary! 🌟🔮
At the time of writing, minishell is my biggest coding project thus far. It's like creating our own mini-version of the bash shell, but don't let the "mini" part fool you! It took my friend and me more a little more than 1 month to design and implement our solution with bonuses and reach that 42-quality level with zero bugs in our code. 🤯
$?
, $_
and $SHELL
Because why not add a dash of magic? ✨PATH
is not defined, ensuring consistent behavior. 🌟First things first, we all agreed that handling the bonus features would be ideal. So, we structured our entire project to accommodate bonus implementations right from the start. This way, even if we didn’t end up using them, we were prepared. And as it turned out, managing the bonuses wasn’t too challenging! 🌟
Then, we agreed to use https://github.com/RPDJF/betterft with some of my partner functions on this project. This library contains a garbage collector and allow us to ensure that no leaks are made possible. Still, we do not want our memory to grow up each time we malloc, so we still use gfree()
function to free a memory and remove it from the garbage collector. This way, even if we forget to manually free some memory, our garbage will free it for us.
Our solution involved a clear separation between the parser and the executor. This allowed each of us to work independently on our respective parts without waiting for the other.
A token is a well-defined instruction that the executor knows how to execute. It’s like a command waiting to happen! 💡
Here’s what our tokens looks like:
The t_token_type
serves as a simple enumerator to identify the type of token. Whether it’s a command, a pipe, or something else, the executor can deference the data to the corresponding structure based on the token type. 🧐
In this phase, minishell transforms into a wizard, casting spells to execute commands. Here's how the magic unfolds:
Here Documents First!: Just like a wise sorcerer, minishell prioritizes executing here documents (those magical <<
redirections). Why? Because they set the stage for everything else. No other commands should be executed before these mystical incantations. 🔮
Piping: Before execution, Minishell initializes the pipes tokens, updating Token contexts at the same time. It is important to do the piping before stdin and stdout since they have priority. 🛝
Stdin and Stdout Shuffle: Between each pipe context, &&
, or ||
, minishell orchestrates a dance of stdin and stdout. Pipes connect commands like secret tunnels, allowing data to flow seamlessly. And when the curtain rises, stdout takes center stage, revealing the results. 🌊
Command Execution: The grand finale! Minishell steps onto the stage, ready to perform. If a command is recognized as a builtin (like cd
or export
), the corresponding builtin function takes the spotlight. If the builtin operates without pipes, it stays in the same process. But if pipes are involved, it gracefully forks into a new act. 🎭
Command Forks: Regular command executions are always forked. Each command's PID (Process ID) is stored in the command structure. Why? So that when the final curtain falls, minishell waits for all the forks, updates $?
, and prepares for the next prompt. 🌟
&& and || Drama: When &&
or ||
enters the scene, a dramatic waitpid
takes center stage. It updates the command's status property, revealing whether the previous act succeeded or failed. 🎬
Subshells (The Parentheses): Subshells are like hidden chambers within the castle. Minishell forks them, passing data into the executor function. These secret passages allow nested commands to unfold their mysteries. 🏰
Var Init Cancelled: If a command is already in progress, minishell cancels any var initialization. No need to double-cast spells! 🪄
And there you have it—the minishell saga! Feel free to explore our code in the repository. Feedback is always welcome! 🙌
Happy coding, fellow wizards! 🧙♂️🔍