├── shell_practice ├── 0x00-shell │ ├── maxpid.sh │ ├── script.sh │ ├── which │ │ ├── which │ │ ├── cleaner.c │ │ ├── main.h │ │ ├── _getenv.c │ │ ├── tok.c │ │ └── which.c │ ├── hello.c │ ├── printarg.c │ ├── getpid.c │ ├── getppid.c │ ├── myecho.c │ ├── myexecve.c │ ├── environ.c │ ├── printlist.c │ ├── buildenv.c │ ├── mainenv.c │ ├── env_address.c │ ├── notes_setenv.c │ ├── execve.c │ ├── path.c │ ├── wait.c │ ├── torevisit.c │ ├── fork.c │ ├── main.h │ ├── simpgetline.c │ ├── multiexecve.c │ ├── which2.c │ ├── simpleshell.c │ ├── _getenvfull.c │ ├── _getenv.c │ ├── 12-path.c │ ├── simpleshell_v_2_0.c │ ├── which_official.c │ ├── getline.c │ ├── 11_getenv.c │ ├── tok.c │ ├── which3.c │ ├── _setenv.c │ ├── 0-simpleShell.c │ ├── tok3.c │ ├── tok2.c │ ├── pathlist.c │ ├── 14-_setenv2.c │ ├── 13-path_list.c │ └── 16-_setenv.c ├── 0x01-shell │ ├── prompt.c │ ├── _env.c_bac │ ├── helpers_2.c_bac │ ├── simple_shell.1.md │ ├── error.c_bac │ ├── main.c │ ├── _getenv.c │ ├── builtins.c │ ├── builtins_01.c_bac │ ├── shell.h │ ├── error2.c_bac │ ├── path.c │ ├── README.md │ ├── execute.c │ └── helpers.c ├── raymond │ ├── printenviron.c │ ├── _error.c │ ├── shell.h │ ├── shell.c │ └── string.c ├── strsep.c ├── strtok.c ├── strtok_r.c └── sprintf │ └── sprintf.txt ├── test_files ├── test_prompt.c ├── test_get_input.c ├── commands.sh ├── test_find_path.c ├── test_builtins_cd.c ├── test_parse.c ├── test_builtins_exit.c ├── test_get_line.c ├── test_execute.c ├── test_builtins_env.c ├── bettyFixes ├── test_utils.c ├── test_check_for_builtins.c ├── test_builtins_setenv.c ├── test_builtins.c ├── test_env.sh └── checker.bash ├── prompt.c ├── get_path.c ├── builtins_shell_env.c ├── AUTHORS ├── hack ├── generate-authors_2.sh └── generate-authors.sh ├── builtins_shell_exit.c ├── builtins_shell_clear.c ├── get_env.c ├── builtins_shell_cd.c ├── builtins_shell_help.c ├── .gitignore ├── signal_handler.c ├── builtins_check.c ├── error.c ├── main.c ├── _get_line.c ├── builtins_shell_setenv.c ├── LICENSE ├── execute.c ├── find_in_path.c ├── free.c ├── get_input.c ├── parser.c ├── simple_shell.1.md ├── utils_funcs2.c ├── shell.h ├── utils_funcs3.c ├── utils_funcs1.c ├── CODE_OF_CONDUCT.md └── README.md /shell_practice/0x00-shell/maxpid.sh: -------------------------------------------------------------------------------- 1 | cat /proc/sys/kernel/pid_max 2 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/script.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | echo "Hello, world!" 3 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/which/which: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FourtyThree43/simple_shell/HEAD/shell_practice/0x00-shell/which/which -------------------------------------------------------------------------------- /shell_practice/0x00-shell/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | printf("Hello, world!\n"); 6 | return (0); 7 | } 8 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/prompt.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * print_prompt - Print the shell prompt 5 | */ 6 | void print_prompt(void) 7 | { 8 | _puts("$ "); 9 | } 10 | -------------------------------------------------------------------------------- /test_files/test_prompt.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | #include 3 | 4 | int main(void) 5 | { 6 | _puts(("Testing prompt function...\n");) 7 | prompt(); 8 | _puts("\n"); 9 | return (0); 10 | } 11 | -------------------------------------------------------------------------------- /prompt.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * prompt - Print shell prompt to stdin stream. 5 | * 6 | * Return: void. 7 | */ 8 | void prompt(void) 9 | { 10 | _puts(PROMPT); 11 | fflush(stdout); 12 | } 13 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/printarg.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int ac __attribute__((unused)), char **av) 4 | { 5 | int i; 6 | 7 | for (i = 0; av[i]; i++) 8 | printf("%s\n", av[i]); 9 | return (0); 10 | } 11 | -------------------------------------------------------------------------------- /get_path.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * get_path - Returns the value of the PATH enviroment variable. 5 | * 6 | * Return: Pointer to the value of $PATH. 7 | */ 8 | char *get_path(void) 9 | { 10 | return (_getenv("PATH")); 11 | } 12 | -------------------------------------------------------------------------------- /test_files/test_get_input.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | #include 3 | 4 | int main(void) 5 | { 6 | printf("Testing get_input function...\n"); 7 | char *input = get_input(); 8 | printf("Input: %s\n", input); 9 | free(input); 10 | } 11 | -------------------------------------------------------------------------------- /test_files/commands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #$ ./hsh < commands.sh 4 | ls -l; pwd; echo "Hello, world!"; date 5 | 6 | ls && echo "success" 7 | pwd || echo "failure" 8 | echo "Hello" || echo "World" && echo "Goodbye" 9 | echo "Testing" && false || echo "Success" 10 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/getpid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /** 5 | * main - PID 6 | * 7 | * Return: Always 0. 8 | */ 9 | int main(void) 10 | { 11 | pid_t my_pid; 12 | 13 | my_pid = getpid(); 14 | printf("%u\n", my_pid); 15 | return (0); 16 | } 17 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/getppid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /** 5 | * main - PID 6 | * 7 | * Return: Always 0. 8 | */ 9 | int main(void) 10 | { 11 | pid_t my_pid; 12 | 13 | my_pid = getppid(); 14 | printf("%u\n", my_pid); 15 | return (0); 16 | } 17 | -------------------------------------------------------------------------------- /shell_practice/raymond/printenviron.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * printenviron - print the current environment 5 | * 6 | * Return: void. 7 | */ 8 | void printenviron(char **ev) 9 | { 10 | unsigned int i; 11 | 12 | for (i = 0; ev[i]; i++) 13 | _puts(ev[i]), _putchar('\n'); 14 | } 15 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/myecho.c: -------------------------------------------------------------------------------- 1 | /* myecho.c */ 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(int argc, char *argv[]) 8 | { 9 | int j; 10 | 11 | for (j = 0; j < argc; j++) 12 | printf("argv[%d]: %s\n", j, argv[j]); 13 | 14 | exit(EXIT_SUCCESS); 15 | } 16 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/myexecve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void) 6 | { 7 | char *argv[] = {"/usr/bin/ls", NULL}; 8 | if (execve(argv[0], argv, NULL) == -1) 9 | perror("Error"); 10 | printf("You shouldn't be seeing this.\n"); 11 | return (0); 12 | } 13 | -------------------------------------------------------------------------------- /test_files/test_find_path.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | #include 3 | 4 | int main(void) 5 | { 6 | char *path = get_path(); 7 | printf("PATH = %s\n", path); 8 | 9 | char *cmd = "ls"; 10 | char *fullpath = find_in_path(cmd); 11 | printf("Full path for %s: %s\n", cmd, fullpath); 12 | 13 | return (0); 14 | } 15 | -------------------------------------------------------------------------------- /builtins_shell_env.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * shell_env - Prints all the environment variables. 5 | * 6 | * Return: void. 7 | */ 8 | int shell_env(void) 9 | { 10 | int i; 11 | 12 | for (i = 0; environ[i]; i++) 13 | { 14 | _puts(environ[i]); 15 | _putchar('\n'); 16 | } 17 | 18 | return (0); 19 | } 20 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/environ.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | 5 | /* 6 | * main - print the current environment 7 | * 8 | * Return: 0. 9 | */ 10 | int main(void) 11 | { 12 | unsigned int i; 13 | 14 | for (i = 0; environ[i]; i++) 15 | puts(environ[i]); 16 | return (0); 17 | } 18 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/which/cleaner.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | /** 4 | * cleaner - frees memory allocated dynamically by tokenize() 5 | * @ptr: pointer to allocated memory 6 | * 7 | * Return: void. 8 | */ 9 | void cleaner(char **ptr) 10 | { 11 | for (int i = 0; ptr[i]; i++) 12 | free((ptr[i])); 13 | free(ptr); 14 | } 15 | -------------------------------------------------------------------------------- /test_files/test_builtins_cd.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | 3 | int main(void) 4 | { 5 | char *dir = _getenv("PWD"); 6 | printf("Current directory: %s\n", dir); 7 | 8 | char *args[] = {"cd", "..", NULL}; 9 | shell_cd(args); 10 | 11 | dir = _getenv("PWD"); 12 | printf("Current directory: %s\n", dir); 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # File @generated by hack/generate-authors.sh. DO NOT EDIT. 2 | # This file lists all contributors to the repository. 3 | # See hack/generate-authors.sh to make modifications. 4 | FourtyThree43 <110453964+FourtyThree43@users.noreply.github.com> 5 | FourtyThree43 6 | Kemboiray <113639995+Kemboiray@users.noreply.github.com> 7 | -------------------------------------------------------------------------------- /hack/generate-authors_2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 3 | ROOTDIR="$(git -C "$SCRIPTDIR" rev-parse --show-toplevel)" 4 | 5 | git shortlog -se \ 6 | | perl -spe 's/^\s+\d+\s+//' \ 7 | | sed -e '/^CommitSyncScript.*$/d' \ 8 | > "${ROOTDIR}/AUTHORS" 9 | 10 | figlet "Contributors" >> "${ROOTDIR}/AUTHORS" 11 | -------------------------------------------------------------------------------- /builtins_shell_exit.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * shell_exit - Exit the shell. 5 | * @args: Arguments. 6 | * 7 | * Return: Nothing. 8 | */ 9 | void shell_exit(char **args) 10 | { 11 | int status = 0; 12 | 13 | if (args[1] != NULL) 14 | { 15 | status = _atoi(args[1]); 16 | } 17 | free_tokens(args); 18 | free_last_input(); 19 | exit(status); 20 | } 21 | -------------------------------------------------------------------------------- /builtins_shell_clear.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * shell_clear - clears the terminal screen. 5 | * @args: an array of arguments 6 | * 7 | * Return: 1 to continue executing, 8 | * or 0 to exit. 9 | */ 10 | int shell_clear(char **args) 11 | { 12 | (void)args; /* avoid "unsued parameter" warning */ 13 | _puts("\033[2J\033[H"); 14 | return (1); 15 | } 16 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/_env.c_bac: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _env - prints the current environment 5 | * @env: array of environment variables 6 | * 7 | * Return: always returns 0 8 | */ 9 | int _env(char **env) 10 | { 11 | int i; 12 | 13 | for (i = 0; env[i]; i++) 14 | _puts(env[i]), _putchar('\n'); 15 | 16 | return (0); 17 | } 18 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/printlist.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | /** 4 | * print_path_list - prints a path_list linked list 5 | * @head: pointer to beginning of list 6 | * 7 | * Return: void. 8 | */ 9 | void print_path_list(path_list *head) 10 | { 11 | path_list *temp = head; 12 | 13 | while(temp) 14 | { 15 | puts(temp->dir_node); 16 | temp = temp->next; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test_files/test_parse.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | #include 3 | 4 | int main(void) 5 | { 6 | char *input = "ls -l /usr/bin"; 7 | char **tokens = tokenize_input(input); 8 | 9 | _puts("Testing prompt function...\n"); 10 | for (int i = 0; tokens[i] != NULL; i++) 11 | { 12 | printf("Token %d: %s\n", i, tokens[i]); 13 | } 14 | 15 | free_tokens(tokens); 16 | 17 | return (0); 18 | } 19 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/which/main.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_H 2 | #define MAIN_H 3 | #define _GNU_SOURCE 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | char *_getenv(const char *name); 13 | char **tokenize(char *str, const char *delim); 14 | void cleaner(char **ptr); 15 | 16 | #endif /* MAIN_H */ 17 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/buildenv.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "pathlist.c" 3 | 4 | path_list *buildenv(void) 5 | { 6 | path_list *head = build_list(environ); 7 | return (head); 8 | } 9 | 10 | int main(void) 11 | { 12 | path_list *head = buildenv(); 13 | path_list *temp = head; 14 | 15 | while(temp) 16 | { 17 | puts(temp->dir_node); 18 | temp = temp->next; 19 | } 20 | free_list(head, 0); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/mainenv.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | * main - print the current environment 5 | * @ac: arg count 6 | * @av: arg vector 7 | * @env: pointer to environment 8 | * 9 | * Return: 0. 10 | */ 11 | int main(int ac __attribute__ ((unused)), char **av __attribute__ ((unused)), \ 12 | char **env) 13 | { 14 | unsigned int i; 15 | 16 | for (i = 0; env[i]; i++) 17 | puts(env[i]); 18 | return (0); 19 | } 20 | -------------------------------------------------------------------------------- /test_files/test_builtins_exit.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | 3 | int main(void) 4 | { 5 | char *args1[] = {"exit", "0", NULL}; 6 | char *args2[] = {"exit", "123", NULL}; 7 | 8 | /* Test exit with no arguments */ 9 | shell_exit(args1); 10 | /* This should exit the shell with status code 0 */ 11 | 12 | /* Test exit with argument */ 13 | shell_exit(args2); 14 | /* This should exit the shell with status code 123 */ 15 | 16 | return (0); 17 | } 18 | -------------------------------------------------------------------------------- /test_files/test_get_line.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | 3 | int main(void) 4 | { 5 | char *input_str; 6 | 7 | while (1) 8 | { 9 | input_str = get_line(); 10 | if (input_str == NULL) 11 | { 12 | perror("my_getline"); 13 | exit(EXIT_FAILURE); 14 | } 15 | 16 | if (strcmp(input_str, "exit") == 0) 17 | break; 18 | 19 | printf("You entered: %s\n", input_str); 20 | free(input_str); 21 | } 22 | 23 | printf("Goodbye!\n"); 24 | return (0); 25 | } 26 | -------------------------------------------------------------------------------- /shell_practice/raymond/_error.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _error - frees alloc'd pointers following system error 5 | * @argv: pointer to a pointer to an array of pointers 6 | * @arg: pointer to a pointer to an array of characters 7 | * 8 | * Return: void. 9 | */ 10 | void _error(char ***argv, char **arg) 11 | { 12 | int i; 13 | 14 | for (i = 0; argv[i]; i++) 15 | free(argv[i]); 16 | free(argv); 17 | free(arg); 18 | _putchar('\n'); 19 | exit(EXIT_FAILURE); 20 | } 21 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/env_address.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | 5 | /* 6 | * main - print the addresses of env and environ respectively 7 | * @ac: arg count 8 | * @av: arg vector 9 | * @env: pointer to environment 10 | * 11 | * Return: 0. 12 | */ 13 | int main(int ac __attribute__ ((unused)), char **av __attribute__ ((unused)), char **env) 14 | { 15 | printf("&env: %p\n", &env); 16 | printf("&environ: %p\n", &environ); 17 | return (0); 18 | } 19 | -------------------------------------------------------------------------------- /test_files/test_execute.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | #include 3 | 4 | int main(void) 5 | { 6 | printf("Testing execute function...\n"); 7 | char *input = get_input(); 8 | // char *input = "ls -l /usr/bin"; 9 | char **args = tokenize_input(input); 10 | 11 | //char *args[] = {"a", NULL, NULL}; 12 | execute(args); 13 | 14 | // args[0] = "echo"; 15 | // args[1] = "hello, world!"; 16 | // args[2] = NULL; 17 | // execute(args); 18 | 19 | free(input); 20 | free_tokens(args); 21 | return (0); 22 | } 23 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/notes_setenv.c: -------------------------------------------------------------------------------- 1 | 2 | /* notes */ 3 | /* 4 | - use _getenv() to check if name exists in the environment 5 | - if it does, check if overwrite is non zero. 6 | - if `overwrite` == 0, return 0 (success). 7 | - otherwise, change the relevant string. Parse the list using a temp pointer to locate the appropriate node. 8 | - if it does not (i.e NULL is returned): 9 | - Add a node at the end of the list. 10 | - Initialise the first member with `value` and the second with NULL. 11 | 12 | */ 13 | -------------------------------------------------------------------------------- /test_files/test_builtins_env.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | 3 | int main(void) 4 | { 5 | char **args; 6 | char *cmd = "env"; 7 | 8 | args = tokenize_input(cmd); 9 | if (args == NULL || *args == NULL) 10 | { 11 | fprintf(stderr, "Failed to tokenize input\n"); 12 | return (EXIT_FAILURE); 13 | } 14 | 15 | if (execute(args) != 0) 16 | { 17 | fprintf(stderr, "Failed to execute command: %s\n", cmd); 18 | free_tokens(args); 19 | return (EXIT_FAILURE); 20 | } 21 | 22 | free_tokens(args); 23 | return (EXIT_SUCCESS); 24 | } 25 | -------------------------------------------------------------------------------- /get_env.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _getenv - Get the value of an environment variable 5 | * @name: Name of the environment variable 6 | * 7 | * Return: Value of the environment variable, or NULL if it doesn't exist 8 | */ 9 | char *_getenv(const char *name) 10 | { 11 | char **env; 12 | size_t name_len = _strlen(name); 13 | 14 | for (env = environ; *env != NULL; env++) 15 | { 16 | if (_strncmp(*env, name, name_len) == 0 && (*env)[name_len] == '=') 17 | { 18 | return (&(*env)[name_len + 1]); 19 | } 20 | } 21 | 22 | return (NULL); 23 | } 24 | -------------------------------------------------------------------------------- /test_files/bettyFixes: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | my $TAB_WIDTH = 4; 7 | 8 | my @files = `find . -name "*.c"`; 9 | 10 | foreach my $file (@files) { 11 | chomp($file); 12 | 13 | # Remove trailing white spaces 14 | `perl -pi -e 's/[[:space:]]*\$//g' $file`; 15 | 16 | # Convert end-of-line sequences to LF 17 | `perl -pi -e 's/\r\n|\r/\n/g' $file`; 18 | 19 | # Convert indents to tabs 20 | `perl -pi -e 's{^(( {$TAB_WIDTH})+) }{substr("\t" x length(\$1), 0, $TAB_WIDTH)}e' $file`; 21 | } 22 | -------------------------------------------------------------------------------- /builtins_shell_cd.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * shell_cd - changes the current working directory of the shell 5 | * @args: array of arguments 6 | */ 7 | void shell_cd(char **args) 8 | { 9 | char *dir = args[1]; 10 | int ret; 11 | 12 | /* If no argument is provided, change to HOME directory */ 13 | if (dir == NULL) 14 | { 15 | dir = _getenv("HOME"); 16 | if (dir == NULL) 17 | { 18 | _puts("cd: No HOME directory found\n"); 19 | return; 20 | } 21 | } 22 | 23 | ret = chdir(dir); 24 | if (ret == -1) 25 | { 26 | perror("cd"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /hack/generate-authors.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 6 | ROOTDIR="$(git -C "$SCRIPTDIR" rev-parse --show-toplevel)" 7 | 8 | set -x 9 | 10 | # see also ".mailmap" for how email addresses and names are deduplicated 11 | cat > "${ROOTDIR}/AUTHORS" <<- EOF 12 | # File @generated by hack/generate-authors.sh. DO NOT EDIT. 13 | # This file lists all contributors to the repository. 14 | # See hack/generate-authors.sh to make modifications. 15 | $(git -C "$ROOTDIR" log --format='%aN <%aE>' | LC_ALL=C.UTF-8 sort -uf) 16 | EOF 17 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/execve.c: -------------------------------------------------------------------------------- 1 | /* execve.c */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int 8 | main(int argc, char *argv[]) 9 | { 10 | char *newargv[] = { NULL, "hello", "world", "program", NULL }; 11 | char *newenviron[] = { NULL }; 12 | 13 | if (argc != 2) { 14 | fprintf(stderr, "Usage: %s \n", argv[0]); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | newargv[0] = argv[1]; 19 | 20 | execve(argv[1], newargv, newenviron); 21 | perror("execve"); /* execve() returns only on error */ 22 | exit(EXIT_FAILURE); 23 | } 24 | -------------------------------------------------------------------------------- /builtins_shell_help.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * shell_help - displays help information for built-in commands 5 | */ 6 | void shell_help(void) 7 | { 8 | _puts("\nShell Version 1.0.0\n\n"); 9 | _puts("Usage: ./hsh\n\n"); 10 | _puts("Shell built-in commands:\n\n"); 11 | _puts("help\t\tDisplay this help information\n\n"); 12 | _puts("cd [dir]\tChange the current working directory\n\n"); 13 | _puts("env\t\tDisplay the environment variables\n\n"); 14 | _puts("setenv\t\tSet an environment variable\n\n"); 15 | _puts("unsetenv\tUnset an environment variable\n\n"); 16 | _puts("exit\t\tExit the shell\n\n"); 17 | } 18 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/path.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "tok.c" 3 | #include "_getenv.c" 4 | 5 | /** 6 | * print_path - prints each directory contained in $PATH 7 | * 8 | * Return: EXIT_SUCCESS. 9 | */ 10 | void print_path(void) 11 | { 12 | char *path = _getenv("PATH"); 13 | char *str = path; 14 | char **dir = tokenize(str, ":"); 15 | unsigned int i; 16 | 17 | if (!(path)) 18 | dprintf(2, "$PATH not found!\n"), exit(EXIT_FAILURE); 19 | for (i = 0; dir[i]; i++) 20 | { 21 | puts(dir[i]); 22 | free(dir[i]); 23 | } 24 | free(dir); 25 | } 26 | 27 | int main(void) 28 | { 29 | print_path(); 30 | exit(EXIT_SUCCESS); 31 | } -------------------------------------------------------------------------------- /shell_practice/0x01-shell/helpers_2.c_bac: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _atoi - converts a string to an integer. 5 | * @s: string to convert. 6 | * 7 | * Return: integer value of the string, 8 | * or -1 if the string is not a valid number. 9 | */ 10 | int _atoi(char *s) 11 | { 12 | int sign = 1, i = 0, num = 0; 13 | 14 | if (s == NULL) 15 | return (-1); 16 | 17 | if (s[i] == '-') 18 | { 19 | sign = -1; 20 | i++; 21 | } 22 | 23 | while (s[i] != '\0') 24 | { 25 | if (s[i] >= '0' && s[i] <= '9') 26 | num = num * 10 + (s[i] - '0'); 27 | else 28 | return (-1); 29 | 30 | i++; 31 | } 32 | 33 | return (num * sign); 34 | } 35 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/wait.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /** 8 | * main - print nos. 1 - 5 and 6 - 10 in child and parent processes 9 | * respectively 10 | * 11 | * Return: 0. 12 | */ 13 | int main(void) 14 | { 15 | int pid = fork(); 16 | int n; 17 | 18 | if (pid < 0) 19 | perror("Error"); 20 | if (pid == 0) 21 | { 22 | n = 1; 23 | } 24 | else 25 | { 26 | n = 6; 27 | wait(NULL); 28 | } 29 | 30 | for (int i = n; i < n + 5; i++) 31 | { 32 | printf(" %d", i); 33 | if (i == 10) 34 | putchar(10); 35 | fflush(stdout); 36 | } 37 | 38 | return (0); 39 | } 40 | -------------------------------------------------------------------------------- /test_files/test_utils.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | #include 3 | 4 | int main(void) 5 | { 6 | char *str = "Hello, world!"; 7 | char *str2; 8 | printf("%s\n", str); 9 | 10 | printf("Length of string: %d\n", _strlen(str)); 11 | 12 | char *copy = _strcpy(str, str2); 13 | printf("Copy of string: %s\n", copy); 14 | //free(copy); 15 | 16 | char *cat = _strcat(str2, " This is a test."); 17 | printf("Concatenated string: %s\n", cat); 18 | //free(cat); 19 | 20 | char *dup = _strdup(str2); 21 | printf("Duplicate of string: %s\n", dup); 22 | //free(dup); 23 | 24 | char *substring = _strstr(str2, "world"); 25 | printf("Substring: %s\n", substring); 26 | 27 | return (0); 28 | } 29 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/torevisit.c: -------------------------------------------------------------------------------- 1 | char **tmp = NULL; 2 | unsigned int i, j = 1; 3 | 4 | if (line[nread - 2] == 92) 5 | { 6 | printf("> "); 7 | tmp = malloc(sizeof(tmp)); 8 | //check for malloc failure 9 | tmp[0] = malloc(nread); 10 | //check for malloc failure 11 | strcpy(tmp[0], line); 12 | 13 | for (i = 0, j = 1; ((nread = getline(&line, &len, stdin)) != -1) && (line[nread - 2] == 92); i++, j++) 14 | { 15 | tmp = realloc(tmp, j + 1); 16 | //check for malloc failure 17 | tmp[j] = malloc(nread); 18 | //check for malloc failure 19 | } 20 | tmp[j] = NULL; 21 | for (j = 0; tmp[j]; j++) 22 | { 23 | fwrite(tmp[j], 1, strlen(tmp[j]), stdout); 24 | printf("> "); 25 | } 26 | continue; 27 | } 28 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/fork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void) 6 | { 7 | pid_t pid; 8 | 9 | printf("Before fork:\n"); 10 | printf("PID = %u, PPID = %u\n", getpid(), getppid()); 11 | 12 | pid = fork(); 13 | if (pid == -1) 14 | perror("fork() failure"); 15 | 16 | if (pid == 0) 17 | { 18 | printf("Before sleep:\nPID = %u, PPID = %u\n", getpid(), getppid()); 19 | sleep(10); 20 | printf("Child process:\n"); 21 | printf("After sleep:\nPID = %u, PPID = %u\n", getpid(), getppid()); 22 | } 23 | 24 | else 25 | { 26 | printf("Parent process exiting...\n"); 27 | } 28 | return (0); 29 | } 30 | -------------------------------------------------------------------------------- /shell_practice/strsep.c: -------------------------------------------------------------------------------- 1 | /* strsep */ 2 | #include "shell.h" 3 | #include 4 | #include 5 | 6 | char* my_strsep(char** str_ptr, const char* delim) 7 | { 8 | if (*str_ptr == NULL) 9 | return (NULL); 10 | 11 | char* token_start = *str_ptr; 12 | 13 | *str_ptr = strpbrk(token_start, delim); 14 | 15 | if (*str_ptr != NULL) 16 | { 17 | *(*str_ptr)++ = '\0'; 18 | } 19 | return (token_start); 20 | } 21 | 22 | int main() 23 | { 24 | char str[] = "The quick brown fox jumps over the lazy dog"; 25 | char delim[] = " "; 26 | char *token, *remaining_str; 27 | 28 | remaining_str = str; 29 | 30 | while ((token = my_strsep(&remaining_str, delim)) != NULL) 31 | { 32 | printf("%s\n", token); 33 | } 34 | return (0); 35 | } 36 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/main.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_H 2 | #define MAIN_H 3 | #define _GNU_SOURCE 4 | 5 | /* Header Files */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef struct path_list{ 12 | char *dir_node; 13 | struct path_list *next; 14 | } path_list; 15 | 16 | /* Function Prototypes */ 17 | char **tokenize(char *str, const char *delim); 18 | char *_getenv(const char *name); 19 | char *_getenvfull(const char *name); 20 | void print_path(void); 21 | char **path_ptrs(void); 22 | path_list *build_list(char **ptr); 23 | void free_list(path_list *head, int tok); 24 | int _setenv(const char *name, const char *value, int overwrite); 25 | void print_path_list(path_list *head); 26 | 27 | #endif /* MAIN_H */ 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | rsh 39 | 40 | # Debug files 41 | *.dSYM/ 42 | *.su 43 | *.idb 44 | *.pdb 45 | 46 | # Kernel Module Compile Results 47 | *.mod* 48 | *.cmd 49 | .tmp_versions/ 50 | modules.order 51 | Module.symvers 52 | Mkfile.old 53 | dkms.conf 54 | 55 | # Test files 56 | test/ 57 | *bac 58 | 59 | #miscellaneous 60 | .vscode 61 | -------------------------------------------------------------------------------- /signal_handler.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * handle_sigint - Signal handler for SIGINT (Ctrl+C) 5 | * @sig: Signal number 6 | * 7 | * Return: Nothing 8 | */ 9 | void handle_sigint(int sig) 10 | { 11 | (void) sig; 12 | _putchar('\n'); 13 | prompt(); 14 | } 15 | 16 | /** 17 | * handle_sigquit - Signal handler for SIGQUIT (Ctrl+\) 18 | * @sig: Signal number 19 | * 20 | * Return: Nothing 21 | */ 22 | void handle_sigquit(int sig) 23 | { 24 | (void) sig; 25 | _puterror("Quit (core dumped)\n"); 26 | exit(EXIT_SUCCESS); 27 | } 28 | 29 | /** 30 | * handle_sigstp - Signal handler for SIGTSTP (Ctrl+Z) 31 | * @sig: Signal number 32 | * 33 | * Return: Nothing 34 | */ 35 | void handle_sigstp(int sig) 36 | { 37 | (void) sig; 38 | _puts("\n"); 39 | prompt(); 40 | } 41 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/simpgetline.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | char *line = NULL; 9 | size_t len = 0; 10 | ssize_t nread; 11 | 12 | if (argc != 1) { 13 | fprintf(stderr, "Usage: %s\n", argv[0]); 14 | exit(EXIT_FAILURE); 15 | } 16 | 17 | printf("$ "); 18 | while ((nread = getline(&line, &len, stdin)) != -1) 19 | { 20 | if (strcmp(line, "exit\n") == 0){ 21 | free(line); 22 | exit(EXIT_SUCCESS); 23 | } 24 | if (strcmp(line, "\n") == 0) 25 | { 26 | printf("$ "); 27 | continue; 28 | } 29 | fwrite(line, 1, nread, stdout); 30 | printf("$ "); 31 | } 32 | free(line); 33 | putchar(10); 34 | exit(EXIT_SUCCESS); 35 | } 36 | -------------------------------------------------------------------------------- /builtins_check.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * check_for_builtin - checks if the command is a builtin 5 | * @args: the arguments array 6 | * 7 | * Return: 1 if command is a builtin, 0 otherwise 8 | */ 9 | int check_for_builtin(char **args) 10 | { 11 | if (!args[0]) 12 | return (0); 13 | if (!_strcmp(args[0], "exit")) 14 | shell_exit(args); 15 | else if (!_strcmp(args[0], "env")) 16 | shell_env(); 17 | else if (!_strcmp(args[0], "setenv")) 18 | shell_setenv(args); 19 | else if (!_strcmp(args[0], "unsetenv")) 20 | shell_unsetenv(args); 21 | else if (!_strcmp(args[0], "help")) 22 | shell_help(); 23 | else if (!_strcmp(args[0], "cd")) 24 | shell_cd(args); 25 | else if (!_strcmp(args[0], "clear")) 26 | shell_clear(args); 27 | else 28 | return (0); 29 | return (1); 30 | } 31 | -------------------------------------------------------------------------------- /error.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _puts - Prints a string to the standard output stream 5 | * @str: The string to print 6 | * 7 | * Return: Void 8 | */ 9 | void _puts(char *str) 10 | { 11 | size_t len; 12 | ssize_t num_written; 13 | 14 | len = _strlen(str); 15 | num_written = write(STDOUT_FILENO, str, len); 16 | if (num_written == -1) 17 | { 18 | perror("write"); 19 | } 20 | } 21 | 22 | /** 23 | * _puterror - Prints an error message to the standard error stream 24 | * @err: The error message to print 25 | * 26 | * Return: Void 27 | */ 28 | void _puterror(char *err) 29 | { 30 | size_t len; 31 | ssize_t num_written; 32 | 33 | len = _strlen(err); 34 | num_written = write(STDERR_FILENO, err, len); 35 | if (num_written == -1) 36 | { 37 | perror("write"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/simple_shell.1.md: -------------------------------------------------------------------------------- 1 | # NAME 2 | 3 | simple_shell - a simple UNIX command line interpreter 4 | 5 | # SYNOPSIS 6 | 7 | **simple_shell** 8 | 9 | # DESCRIPTION 10 | 11 | This is a simple UNIX command line interpreter that is capable of executing basic commands and scripts. It was written as part of a ALX School project. 12 | 13 | # OPTIONS 14 | 15 | None. 16 | 17 | # EXIT STATUS 18 | 19 | The simple_shell command returns 0 on success and non-zero on failure. 20 | 21 | # EXAMPLES 22 | 23 | To run a command, simply enter it at the prompt: 24 | 25 | `$ /bin/ls` 26 | 27 | 28 | To exit the shell, use the `exit` command: 29 | 30 | `$ exit` 31 | 32 | 33 | # AUTHORS 34 | 35 | This program was written by FourtyThree43 and Kemboiray. 36 | 37 | # SEE ALSO 38 | 39 | bash(1), sh(1), ksh(1) 40 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/multiexecve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /** 8 | * main - run a program in 5 child processes of same parent 9 | * 10 | * Return: EXIT_SUCCESS. 11 | */ 12 | int main(void) 13 | { 14 | pid_t pid; 15 | int i, status; 16 | 17 | for (i = 0; i < 5; i++) 18 | { 19 | pid = fork(); 20 | if (pid == -1) 21 | { 22 | perror("fork() error"); 23 | exit(EXIT_FAILURE); 24 | } 25 | if (pid == 0) 26 | { 27 | char *argv[] = {"hello", NULL}; 28 | 29 | if (execve(argv[0], argv, NULL) == -1) 30 | { 31 | perror("execve() error"); 32 | exit(EXIT_FAILURE); 33 | } 34 | } 35 | else 36 | { 37 | wait(&status); 38 | } 39 | } 40 | 41 | if (pid != 0) 42 | exit(EXIT_SUCCESS); 43 | } 44 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/error.c_bac: -------------------------------------------------------------------------------- 1 | #include "error.h" 2 | 3 | /** 4 | * _puterror - writes an error message to standard error 5 | * @str: the string to write 6 | */ 7 | void _puterror(char *str) 8 | { 9 | size_t len = strlen(str); 10 | ssize_t w = write(STDERR_FILENO, str, len); 11 | 12 | if (w == -1) 13 | { 14 | char *msg = "Error: Cannot write to STDERR\n"; 15 | write(STDERR_FILENO, msg, strlen(msg)); 16 | exit(EXIT_FAILURE); 17 | } 18 | } 19 | 20 | /** 21 | * print_error - prints an error message with additional information 22 | * @command: the command that was executed 23 | * @message: the error message 24 | */ 25 | void print_error(char *command, char *message) 26 | { 27 | char error_message[BUFSIZE]; 28 | int len = sprintf(error_message, "%s: %s\n", command, message); 29 | _puterror(error_message); 30 | } 31 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/main.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * main - Entry point for the shell 5 | * 6 | * Return: Always 0 7 | */ 8 | int main(void) 9 | { 10 | char *line; /* Initialize to NULL */ 11 | char **args; /* Initialize to NULL */ 12 | int status = 1; 13 | size_t bufsize = 0; 14 | 15 | while (status) 16 | { 17 | print_prompt(); 18 | if (getline(&line, &bufsize, stdin) == -1) /* Check for EOF or error */ 19 | { 20 | free(line); 21 | break; 22 | } 23 | args = tokenize(line, " \n\r\t\a"); 24 | if (args == NULL || *args == NULL) /* Check for empty line */ 25 | { 26 | free_tokens(args); 27 | continue; 28 | } 29 | status = execute(args, get_path(environ)); 30 | free_tokens(args); 31 | } 32 | 33 | free(line); /* Free memory used for input line */ 34 | 35 | return (0); 36 | } 37 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * main - implements a simple shell 5 | * 6 | * Return: EXIT_SUCCESS. 7 | */ 8 | int main(void) 9 | { 10 | char *input; 11 | char **args; 12 | int status; 13 | 14 | /* Register signal handlers */ 15 | signal(SIGINT, handle_sigint); 16 | signal(SIGQUIT, handle_sigquit); 17 | signal(SIGTSTP, handle_sigstp); 18 | 19 | do { 20 | input = get_input(); 21 | if (!input || !*input)/* EOF detected, exit the loop */ 22 | break; 23 | 24 | args = tokenize_input(input); 25 | if (!args || !*args) 26 | { 27 | free(input); 28 | free_tokens(args); 29 | continue; 30 | } 31 | status = execute(args); 32 | free(input); 33 | free_tokens(args); 34 | 35 | /* Set status to 1 to continue the loop */ 36 | status = 1; 37 | } while (status); 38 | 39 | return (EXIT_SUCCESS); 40 | } 41 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/_getenv.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _getenv - function that gets an environment variable. 5 | * @name: name of the environment variable. 6 | * 7 | * Return: pointer to the value of the environment variable, 8 | * or NULL if not found. 9 | */ 10 | char *_getenv(char *name) 11 | { 12 | char *value = NULL; 13 | int i, len; 14 | 15 | if (name == NULL) 16 | return (NULL); 17 | 18 | len = _strlen(name); 19 | 20 | for (i = 0; environ[i] != NULL; i++) 21 | { 22 | if (strncmp(name, environ[i], len) == 0 && environ[i][len] == '=') 23 | { 24 | value = environ[i] + len + 1; 25 | break; 26 | } 27 | } 28 | 29 | if (value == NULL) 30 | { 31 | _puterror("getenv: environment variable not found: "); 32 | _puterror(name); 33 | _puterror("\n"); 34 | } 35 | 36 | return (value); 37 | } 38 | -------------------------------------------------------------------------------- /shell_practice/strtok.c: -------------------------------------------------------------------------------- 1 | /* strtok */ 2 | #include "shell.h" 3 | #include 4 | #include 5 | 6 | char* my_strtok(char* str, const char* delim) 7 | { 8 | static char* save_ptr; 9 | 10 | if (str != NULL) 11 | save_ptr = str; 12 | 13 | if (*save_ptr == '\0') 14 | return (NULL); 15 | 16 | 17 | char* token_start = save_ptr; 18 | 19 | while (*save_ptr != '\0' && strchr(delim, *save_ptr) == NULL) 20 | { 21 | save_ptr++; 22 | } 23 | 24 | if (*save_ptr != '\0') 25 | { 26 | *save_ptr++ = '\0'; 27 | } 28 | return (token_start); 29 | } 30 | 31 | int main() 32 | { 33 | char str[] = "The quick brown fox jumps over the lazy dog"; 34 | char delim[] = " "; 35 | char *token = my_strtok(str, delim); 36 | 37 | while (token != NULL) 38 | { 39 | printf("%s\n", token); 40 | token = my_strtok(NULL, delim); 41 | } 42 | return (0); 43 | } 44 | -------------------------------------------------------------------------------- /shell_practice/strtok_r.c: -------------------------------------------------------------------------------- 1 | /*strtok_r*/ 2 | #include "shell.h" 3 | #include 4 | #include 5 | 6 | char* my_strtok_r(char* str, const char* delim, char** save_ptr) 7 | { 8 | if (str != NULL) 9 | *save_ptr = str; 10 | 11 | if (**save_ptr == '\0') 12 | return (NULL); 13 | 14 | char* token_start = *save_ptr; 15 | 16 | while (**save_ptr != '\0' && strchr(delim, **save_ptr) == NULL) 17 | { 18 | (*save_ptr)++; 19 | } 20 | if (**save_ptr != '\0') 21 | { 22 | **save_ptr = '\0'; 23 | (*save_ptr)++; 24 | } 25 | return (token_start); 26 | } 27 | 28 | int main() 29 | { 30 | char str[] = "The quick brown fox jumps over the lazy dog"; 31 | char delim[] = " "; 32 | char *saveptr, *token; 33 | 34 | token = my_strtok_r(str, delim, &saveptr); 35 | 36 | while (token != NULL) 37 | { 38 | printf("%s\n", token); 39 | token = my_strtok_r(NULL, delim, &saveptr); 40 | } 41 | return (0); 42 | } 43 | -------------------------------------------------------------------------------- /test_files/test_check_for_builtins.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | 3 | int main(void) 4 | { 5 | char *args1[] = {"exit", NULL}; 6 | char *args2[] = {"env", NULL}; 7 | char *args3[] = {"setenv", "VAR", "value", NULL}; 8 | char *args4[] = {"unsetenv", "VAR", NULL}; 9 | char *args5[] = {"help", NULL}; 10 | char *args6[] = {"cd", NULL}; 11 | char *args7[] = {"ls", NULL}; 12 | 13 | check_for_builtin(args2); /* Should print the environment variables */ 14 | check_for_builtin(args3); /* Should set the environment variable VAR to value */ 15 | check_for_builtin(args4); /* Should unset the environment variable VAR */ 16 | check_for_builtin(args5); /* Should print help information */ 17 | check_for_builtin(args6); /* Should change the current directory to /home/fourtythree43/*/ 18 | check_for_builtin(args7); /* Should not do anything */ 19 | //check_for_builtin(args1); /* Should exit the shell */ 20 | return (0); 21 | } 22 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/which2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int ac, char **av) 10 | { 11 | char *str, pathname[1024]; 12 | struct stat st; 13 | int i = 1, error = 0, idx, tmp, j; 14 | 15 | memset(pathname, 0, 1024); 16 | 17 | if (ac < 2) 18 | { 19 | dprintf(2, "Usage: %s ...\n", av[0]); 20 | return (1); 21 | } 22 | 23 | str = "/home/kemboiray/ALX-Local/simple_shell/shell_practice/0x00-shell/"; 24 | for (idx = 0; str[idx]; idx++) 25 | pathname[idx] = str[idx]; 26 | 27 | while (av[i]) 28 | { 29 | tmp = idx; 30 | for (j = 0; (av[i])[j]; tmp++, j++) 31 | pathname[tmp] = (av[i])[j]; 32 | if(stat(av[i], &st) == 0) 33 | puts(pathname); 34 | else 35 | error = 1; 36 | i++; 37 | } 38 | if (error == 1) 39 | dprintf(2, " "); 40 | return (error); 41 | } 42 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/simpleshell.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(void) 9 | { 10 | char *argv[] = {NULL, NULL}; 11 | size_t len = 0; 12 | ssize_t nread; 13 | pid_t id; 14 | int status; 15 | 16 | printf("$ "); 17 | while((nread = getline(&(argv[0]), &len, stdin)) != -1) 18 | { 19 | if (strcmp(argv[0], "exit\n") == 0) 20 | break; 21 | if ((id = fork()) == -1) 22 | { 23 | perror("Error (fork)"); 24 | exit(EXIT_FAILURE); 25 | } 26 | if (id == 0) 27 | { 28 | (argv[0])[nread - 1] = '\0'; 29 | 30 | if (execve(argv[0], argv, NULL) == -1) 31 | { 32 | perror("Error (execve)"); 33 | free(argv[0]); 34 | exit(EXIT_FAILURE); 35 | } 36 | } 37 | else 38 | { 39 | wait(&status); 40 | free(argv[0]); 41 | argv[0] = NULL; 42 | printf("$ "); 43 | } 44 | } 45 | free(argv[0]); 46 | exit(EXIT_SUCCESS); 47 | } 48 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/_getenvfull.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | char *_getenvfull(const char *name) 4 | { 5 | unsigned int i, idx; 6 | char *buf; 7 | 8 | idx = strlen(name); 9 | buf = calloc(idx + 2, sizeof(char)); 10 | if (!(buf)) 11 | dprintf(2, "calloc() failure\n"), exit(-1); 12 | 13 | for (i = 0; environ[i]; i++) 14 | { 15 | if (!(strcpy(buf, name))) 16 | { 17 | free(buf); 18 | dprintf(2, "strcpy() failure\n"), exit(-1); 19 | } 20 | buf[idx] = '='; 21 | if (strncmp(buf, environ[i], strlen(buf)) == 0) 22 | { 23 | free(buf); 24 | return (environ[i]); 25 | } 26 | } 27 | free(buf); 28 | return (NULL); 29 | } 30 | #if 0 31 | int main(int ac, char **av) 32 | { 33 | int i = 0; 34 | char *val_string; 35 | 36 | if (ac < 2) 37 | dprintf(2, "Usage: %s name ...\n", av[i]), exit(-1); 38 | for (i = 1; av[i]; i++) 39 | { 40 | if ((val_string = _getenv(av[i]))) 41 | puts(val_string); 42 | else 43 | dprintf(2, "%s: not found!\n", av[i]); 44 | } 45 | 46 | exit(0); 47 | } 48 | #endif 49 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/_getenv.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | char *_getenv(const char *name) 4 | { 5 | unsigned int i, idx; 6 | char *buf; 7 | 8 | idx = strlen(name); 9 | buf = calloc(idx + 2, sizeof(char)); 10 | if (!(buf)) 11 | dprintf(2, "calloc() failure\n"), exit(-1); 12 | 13 | for (i = 0; environ[i]; i++) 14 | { 15 | if (!(strcpy(buf, name))) 16 | { 17 | free(buf); 18 | dprintf(2, "strcpy() failure\n"), exit(-1); 19 | } 20 | buf[idx] = '='; 21 | if (strncmp(buf, environ[i], strlen(buf)) == 0) 22 | { 23 | free(buf); 24 | return (environ[i] + idx + 1); 25 | } 26 | } 27 | free(buf); 28 | return (NULL); 29 | } 30 | #if 0 31 | int main(int ac, char **av) 32 | { 33 | int i = 0; 34 | char *val_string; 35 | 36 | if (ac < 2) 37 | dprintf(2, "Usage: %s name ...\n", av[i]), exit(-1); 38 | for (i = 1; av[i]; i++) 39 | { 40 | if ((val_string = _getenv(av[i]))) 41 | puts(val_string); 42 | else 43 | dprintf(2, "%s: not found!\n", av[i]); 44 | } 45 | 46 | exit(0); 47 | } 48 | #endif 49 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/which/_getenv.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | char *_getenv(const char *name) 4 | { 5 | unsigned int i, idx; 6 | char *buf; 7 | 8 | idx = strlen(name); 9 | buf = calloc(idx + 2, sizeof(char)); 10 | if (!(buf)) 11 | dprintf(2, "calloc() failure\n"), exit(-1); 12 | 13 | for (i = 0; environ[i]; i++) 14 | { 15 | if (!(strcpy(buf, name))) 16 | { 17 | free(buf); 18 | dprintf(2, "strcpy() failure\n"), exit(-1); 19 | } 20 | buf[idx] = '='; 21 | if (strncmp(buf, environ[i], strlen(buf)) == 0) 22 | { 23 | free(buf); 24 | return (environ[i] + idx + 1); 25 | } 26 | } 27 | free(buf); 28 | return (NULL); 29 | } 30 | #if 0 31 | int main(int ac, char **av) 32 | { 33 | int i = 0; 34 | char *val_string; 35 | 36 | if (ac < 2) 37 | dprintf(2, "Usage: %s name ...\n", av[i]), exit(-1); 38 | for (i = 1; av[i]; i++) 39 | { 40 | if ((val_string = _getenv(av[i]))) 41 | puts(val_string); 42 | else 43 | dprintf(2, "%s: not found!\n", av[i]); 44 | } 45 | 46 | exit(0); 47 | } 48 | #endif 49 | -------------------------------------------------------------------------------- /_get_line.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * get_line - Read input from the standard input. 5 | * 6 | * Return: The string enter by the user. 7 | */ 8 | void *get_line(void) 9 | { 10 | static char buffer[BUFFER_SIZE]; 11 | static int buf_pos, buf_size; 12 | char *input_str = NULL; 13 | char current_char; 14 | int input_len = 0; 15 | 16 | while (1) 17 | { 18 | if (buf_pos >= buf_size) 19 | { 20 | buf_size = read(STDIN_FILENO, buffer, BUFFER_SIZE); 21 | buf_pos = 0; 22 | if (buf_size == 0) 23 | return (input_str); 24 | else if (buf_size < 0) 25 | { 26 | perror("read"); 27 | return (NULL); 28 | } 29 | } 30 | 31 | current_char = buffer[buf_pos]; 32 | 33 | buf_pos++; 34 | 35 | if (current_char == '\n') 36 | { 37 | input_str = realloc(input_str, input_len + 1); 38 | input_str[input_len] = '\0'; 39 | return (input_str); 40 | } 41 | else 42 | { 43 | input_str = realloc(input_str, input_len + 1); 44 | input_str[input_len] = current_char; 45 | input_len++; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/12-path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /** 6 | * print_path - prints each directory in the PATH environment variable 7 | */ 8 | void print_path() 9 | { 10 | char *path = getenv("PATH"); 11 | if (path == NULL) 12 | { 13 | printf("PATH environment variable not found\n"); 14 | return; 15 | } 16 | 17 | char *path_copy = strdup(path); 18 | if (path_copy == NULL) 19 | { 20 | printf("Error: out of memory\n"); 21 | return; 22 | } 23 | 24 | char *dir = strtok(path_copy, ":"); 25 | while (dir != NULL) 26 | { 27 | printf("%s\n", dir); 28 | dir = strtok(NULL, ":"); 29 | } 30 | 31 | free(path_copy); 32 | } 33 | 34 | /** 35 | * main - entry point for the program 36 | * @argc: the number of command-line arguments 37 | * @argv: an array of strings containing the command-line arguments 38 | * 39 | * Return: 0 on success, non-zero on error 40 | */ 41 | int main(int argc, char **argv) 42 | { 43 | print_path(); 44 | return EXIT_SUCCESS; 45 | } 46 | -------------------------------------------------------------------------------- /builtins_shell_setenv.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * shell_setenv - Set the value of an environment variable 5 | * @args: Arguments (name and value of the environment variable) 6 | * 7 | * Return: Nothing 8 | */ 9 | int shell_setenv(char **args) 10 | { 11 | char *name, *value; 12 | 13 | if (args[1] == NULL || args[2] == NULL) 14 | { 15 | _puterror("Usage: setenv VARIABLE VALUE\n"); 16 | return (-1); 17 | } 18 | 19 | name = args[1]; 20 | value = args[2]; 21 | 22 | if (setenv(name, value, 1) != 0) 23 | { 24 | _puterror("setenv"); 25 | return (-1); 26 | } 27 | return (0); 28 | } 29 | 30 | /** 31 | * shell_unsetenv - Unset an environment variable 32 | * @args: Arguments (name of the environment variable) 33 | * 34 | * Return: Nothing 35 | */ 36 | int shell_unsetenv(char **args) 37 | { 38 | char *name; 39 | 40 | if (args[1] == NULL) 41 | { 42 | _puterror("Usage: unsetenv VARIABLE\n"); 43 | return (-1); 44 | } 45 | 46 | name = args[1]; 47 | 48 | if (unsetenv(name) != 0) 49 | { 50 | _puterror("unsetenv"); 51 | } 52 | return (0); 53 | } 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 FourtyThree43 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /execute.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * execute - Execute a command with arguments. 5 | * @argv: An array of strings containing the command and its arguments. 6 | * 7 | * Return: The exit status of the executed command. 8 | */ 9 | int execute(char **argv) 10 | { 11 | pid_t id; 12 | int status = 0; 13 | char *cmd_path, *envp[2]; 14 | 15 | if (argv == NULL || *argv == NULL) 16 | return (status); 17 | if (check_for_builtin(argv)) 18 | return (status); 19 | 20 | id = fork(); 21 | if (id < 0) 22 | { 23 | _puterror("fork"); 24 | return (1); 25 | } 26 | if (id == -1) 27 | perror(argv[0]), free_tokens(argv), free_last_input(); 28 | if (id == 0) 29 | { 30 | envp[0] = get_path(); 31 | envp[1] = NULL; 32 | cmd_path = NULL; 33 | if (argv[0][0] != '/') 34 | cmd_path = find_in_path(argv[0]); 35 | if (cmd_path == NULL) 36 | cmd_path = argv[0]; 37 | if (execve(cmd_path, argv, envp) == -1) 38 | { 39 | perror(argv[0]), free_tokens(argv), free_last_input(); 40 | exit(EXIT_FAILURE); 41 | } 42 | } 43 | else 44 | { 45 | do { 46 | waitpid(id, &status, WUNTRACED); 47 | } while (!WIFEXITED(status) && !WIFSIGNALED(status)); 48 | } 49 | return (status); 50 | } 51 | -------------------------------------------------------------------------------- /find_in_path.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * find_in_path - Looks for a command in each directory specified in the PATH 5 | * environment variable 6 | * @command: pointer to `command` string to look for. 7 | * 8 | * Return: pointer to string containing the full path (success) if it is found, 9 | * or NULL if it is not found (failure). 10 | */ 11 | char *find_in_path(char *command) 12 | { 13 | struct stat st; 14 | int stat_ret, i; 15 | char buf[PATH_MAX_LENGTH], *path, *ret, **dir; 16 | 17 | path = get_path(); 18 | if (!path) 19 | return (NULL); 20 | dir = tokenize(path, PATH_SEPARATOR); 21 | if (!dir) 22 | return (NULL); 23 | for (i = 0; dir[i]; i++) 24 | { 25 | _memset(buf, 0, PATH_MAX_LENGTH); 26 | _strcpy(buf, dir[i]); 27 | _strcat(buf, "/"); 28 | _strcat(buf, command); 29 | stat_ret = stat(buf, &st); 30 | if (stat_ret == 0 && S_ISREG(st.st_mode) && (st.st_mode & S_IXUSR)) 31 | { 32 | free_tokens(dir); 33 | ret = malloc(sizeof(char) * (strlen(buf) + 1)); 34 | if (!ret) 35 | return (NULL); 36 | strcpy(ret, buf); 37 | return (ret); 38 | } 39 | } 40 | if (stat_ret == -1) 41 | free_tokens(dir); 42 | return (NULL); 43 | } 44 | -------------------------------------------------------------------------------- /free.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * free_error - frees alloc'd pointers following system error 5 | * @argv: pointer to a pointer to an array of pointers 6 | * @arg: pointer to a pointer to an array of characters 7 | * 8 | * Return: void. 9 | */ 10 | void free_error(char **argv, char *arg) 11 | { 12 | int i; 13 | 14 | for (i = 0; argv[i]; i++) 15 | free(argv[i]); 16 | free(argv); 17 | free(arg); 18 | exit(EXIT_FAILURE); 19 | } 20 | 21 | /** 22 | * free_tokens - frees memory allocated dynamically by tokenize() 23 | * @ptr: pointer to allocated memory 24 | * 25 | * Return: void. 26 | */ 27 | void free_tokens(char **ptr) 28 | { 29 | int i; 30 | 31 | for (i = 0; ptr[i]; i++) 32 | free((ptr[i])); 33 | free(ptr); 34 | } 35 | 36 | 37 | /** 38 | * free_path - Frees the global variable containing the PATH environment 39 | * variable value 40 | * 41 | * Return: Nothing 42 | */ 43 | void free_path(void) 44 | { 45 | if (environ != NULL) 46 | { 47 | size_t i = 0; 48 | 49 | while (environ[i] != NULL) 50 | { 51 | if (_strncmp(environ[i], "PATH=", 5) == 0) 52 | { 53 | free(environ[i]); 54 | environ[i] = NULL; 55 | break; 56 | } 57 | i++; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/simpleshell_v_2_0.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "tok.c" 8 | 9 | int main(void) 10 | { 11 | char *arg = NULL; 12 | char **argv; 13 | size_t len = 0; 14 | ssize_t nread; 15 | pid_t id; 16 | int status, i; 17 | 18 | printf("$ "); 19 | while((nread = getline(&arg, &len, stdin)) != -1) 20 | { 21 | if (strcmp(arg, "exit\n") == 0) 22 | break; 23 | arg[nread - 1] = '\0'; 24 | argv = tokenize(arg, " "); 25 | if ((id = fork()) == -1) 26 | { 27 | perror("Error"); 28 | for (i = 0; argv[i]; i++) 29 | free(argv[i]); 30 | free(argv); 31 | free(arg); 32 | exit(EXIT_FAILURE); 33 | } 34 | if (id == 0) 35 | { 36 | 37 | if (execve(argv[0], argv, NULL) == -1) 38 | { 39 | perror("Error"); 40 | for (i = 0; argv[i]; i++) 41 | free(argv[i]); 42 | free(argv); 43 | free(arg); 44 | exit(EXIT_FAILURE); 45 | } 46 | } 47 | else 48 | { 49 | wait(&status); 50 | for (i = 0; argv[i]; i++) 51 | free(argv[i]); 52 | free(argv); 53 | printf("$ "); 54 | } 55 | } 56 | free(arg); 57 | exit(EXIT_SUCCESS); 58 | } 59 | -------------------------------------------------------------------------------- /shell_practice/raymond/shell.h: -------------------------------------------------------------------------------- 1 | #ifndef _SHELL_H_ 2 | #define _SHELL_H_ 3 | #define _GNU_SOURCE 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /* string.c */ 18 | int _strlen(char *); 19 | int _strcmp(char *, char *); 20 | char *_strstr(char *haystack, char *needle); 21 | char *_strcat(char *, char *); 22 | char *_strchr(char *s, char c); 23 | 24 | /* string1.c */ 25 | char *_strcpy(char *, char *); 26 | char *_strdup(const char *); 27 | void _puts(char *); 28 | int _putchar(char); 29 | int _sprintf(char *str, const char *format, ...); 30 | 31 | /* mem_mgt.c */ 32 | char *_memset(char *, char, unsigned int); 33 | char *_memcpy(char *dest, char *src, unsigned int n); 34 | void *_realloc(void *, unsigned int, unsigned int); 35 | void *_calloc(unsigned int nmemb, unsigned int size); 36 | 37 | /* printenviron.c */ 38 | void printenviron(char **ev); 39 | 40 | /* tok.c */ 41 | char **tokenize(char *str, const char *delim); 42 | 43 | /* _error.c */ 44 | void _error(char ***argv, char **arg); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /get_input.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | static char *last_input; 4 | /** 5 | * get_input - Read the line of input from user. 6 | * 7 | * Return: Pointer to a buffer conatining the user's input. 8 | */ 9 | char *get_input(void) 10 | { 11 | char *input = NULL; 12 | size_t input_size = 0; 13 | ssize_t nread; 14 | 15 | do { 16 | /* print shell prompt */ 17 | prompt(); 18 | 19 | /* get a line of input from user */ 20 | nread = getline(&input, &input_size, stdin); 21 | 22 | /* check for EOF or error */ 23 | if (nread == -1) 24 | { 25 | free(input); 26 | _puts("\n"); 27 | return (NULL); 28 | } 29 | 30 | /* remove trailing newline character */ 31 | input[nread - 1] = '\0'; 32 | 33 | } while (input[0] == '\0' || isspace(input[0])); 34 | 35 | /* update last_input to point to the new input */ 36 | last_input = input; 37 | return (input); 38 | } 39 | 40 | /** 41 | * free_last_input - Frees the most recent input entered by the user. 42 | * 43 | * This function frees the memory allocated for the most recent input string 44 | * entered by the user. It should be called after the input string is no longer 45 | * needed. 46 | */ 47 | void free_last_input(void) 48 | { 49 | free(last_input); 50 | last_input = NULL; 51 | } 52 | -------------------------------------------------------------------------------- /test_files/test_builtins_setenv.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | 3 | int main(void) 4 | { 5 | char *args[] = {"setenv", "MYVAR", "hello", NULL}; 6 | char *unset_args[] = {"unsetenv", "MYVAR", NULL}; 7 | 8 | /* Set an environment variable */ 9 | if (shell_setenv(args) == -1) 10 | { 11 | fprintf(stderr, "Failed to set environment variable\n"); 12 | exit(EXIT_FAILURE); 13 | } 14 | 15 | /* Get the value of the environment variable */ 16 | char *value = getenv("MYVAR"); 17 | if (value == NULL) 18 | { 19 | fprintf(stderr, "Failed to get environment variable\n"); 20 | exit(EXIT_FAILURE); 21 | } 22 | if (strcmp(value, "hello") != 0) 23 | { 24 | fprintf(stderr, "Unexpected environment variable value: %s\n", value); 25 | exit(EXIT_FAILURE); 26 | } 27 | 28 | /* Unset the environment variable */ 29 | if (shell_unsetenv(unset_args) == -1) 30 | { 31 | fprintf(stderr, "Failed to unset environment variable\n"); 32 | exit(EXIT_FAILURE); 33 | } 34 | 35 | /* Get the value of the environment variable again */ 36 | value = getenv("MYVAR"); 37 | if (value != NULL) 38 | { 39 | fprintf(stderr, "Environment variable was not unset\n"); 40 | exit(EXIT_FAILURE); 41 | } 42 | 43 | printf("All tests passed\n"); 44 | return (EXIT_SUCCESS); 45 | } 46 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/which_official.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #define BUFFSIZE 1024 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int ac, char **av) 12 | { 13 | char *cwd, pathname[BUFFSIZE]; 14 | struct stat st; 15 | int i = 1, error = 0, idx, tmp, j, abscheck = 0; 16 | 17 | memset(pathname, 0, BUFFSIZE); 18 | 19 | if (ac < 2) 20 | { 21 | dprintf(2, "Usage: %s ...\n", av[0]); 22 | return (1); 23 | } 24 | 25 | cwd = get_current_dir_name(); 26 | 27 | for (idx = 0; cwd[idx]; idx++) 28 | pathname[idx] = cwd[idx]; 29 | pathname[idx++] = '/'; 30 | 31 | while (av[i]) 32 | { 33 | tmp = idx; 34 | for (j = 0; (av[i])[j]; tmp++, j++) 35 | { 36 | if ((strncmp(av[i], pathname, (unsigned int)idx)) == 0) 37 | { 38 | abscheck = 1; 39 | break; 40 | } 41 | pathname[tmp] = (av[i])[j]; 42 | } 43 | if(stat(av[i], &st) == 0) 44 | { 45 | if (abscheck == 0) 46 | puts(pathname); 47 | else 48 | puts(av[i]); 49 | } 50 | else 51 | error = 1; 52 | 53 | i++; 54 | } 55 | 56 | if (error == 1) 57 | dprintf(2, " "); 58 | 59 | free(cwd); 60 | return (error); 61 | } 62 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/getline.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | char *line = NULL, *tmp = NULL; 9 | size_t len = 0; 10 | ssize_t nread; 11 | int i; 12 | 13 | if (argc != 1) { 14 | fprintf(stderr, "Usage: %s\n", argv[0]); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | printf("$ "); 19 | while ((nread = getline(&line, &len, stdin)) != -1) { 20 | if (strcmp(line, "exit\n") == 0){ 21 | free(line); 22 | exit(EXIT_SUCCESS); 23 | } 24 | if (nread == 1 && line[0] == 10) 25 | { 26 | printf("$ "); 27 | continue; 28 | } 29 | if (line[nread - 2] == '\\'){ 30 | printf("> "); 31 | tmp = malloc(nread); 32 | if (tmp == NULL) 33 | exit(EXIT_FAILURE); 34 | for (i = 0; line[i]; i++) 35 | tmp[i] = line[i]; 36 | continue; 37 | } 38 | if (tmp != NULL){ 39 | for (i = 0; i < strlen(tmp); i++) 40 | { 41 | if ((tmp[i] == 92) && (tmp[i - 1] != 92)) 42 | continue; 43 | putchar(tmp[i]); 44 | } 45 | free(tmp); 46 | tmp = NULL; 47 | } 48 | fwrite(line, 1, nread, stdout); 49 | printf("$ "); 50 | } 51 | free(line); 52 | putchar(10); 53 | exit(EXIT_SUCCESS); 54 | } 55 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/builtins.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * shell_exit - Exit the shell 5 | * @args: Array of arguments 6 | * 7 | * Return: Always returns 0 8 | */ 9 | int shell_exit(char **args) 10 | { 11 | int status = 0; 12 | 13 | if (args[1]) 14 | status = _atoi(args[1]); 15 | 16 | free(args); 17 | exit(status); 18 | } 19 | 20 | /** 21 | * shell_cd - Change the current working directory 22 | * @args: Array of arguments 23 | * 24 | * Return: Always returns 1 25 | */ 26 | int shell_cd(char **args) 27 | { 28 | char *dir = args[1]; 29 | 30 | if (!dir) 31 | dir = _getenv("HOME"); 32 | 33 | if (chdir(dir) == -1) 34 | { 35 | _puterror("cd: can't cd to "); 36 | return (1); 37 | } 38 | 39 | return (1); 40 | } 41 | 42 | /** 43 | * shell_env - Print the environment 44 | * @args: Array of arguments 45 | * 46 | * Return: Always returns 1 47 | */ 48 | int shell_env(void) 49 | { 50 | int i; 51 | 52 | for (i = 0; environ[i]; i++) 53 | _puts(environ[i]); 54 | 55 | return (1); 56 | } 57 | 58 | /** 59 | * _env - prints the current environment 60 | * @env: array of environment variables 61 | * 62 | * Return: always returns 0 63 | */ 64 | int _env(char **env) 65 | { 66 | int i; 67 | 68 | for (i = 0; env[i]; i++) 69 | _puts(env[i]), _putchar('\n'); 70 | 71 | return (0); 72 | } 73 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/11_getenv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /** 6 | * _getenv - retrieves the value of an environment variable by its name 7 | * @name: the name of the environment variable to retrieve 8 | * 9 | * Return: a pointer to the value of the environment variable, or NULL if not found 10 | */ 11 | char *_getenv(const char *name) 12 | { 13 | extern char **environ; 14 | size_t namelen = strlen(name); 15 | 16 | for (char **env = environ; *env != NULL; env++) 17 | { 18 | if (strncmp(name, *env, namelen) == 0 && (*env)[namelen] == '=') 19 | { 20 | return &((*env)[namelen + 1]); 21 | } 22 | } 23 | 24 | return (NULL); 25 | } 26 | 27 | /** 28 | * main - entry point for the program 29 | * @ac: the number of command-line arguments 30 | * @av: an array of strings containing the command-line arguments 31 | * 32 | * Return: 0 on success, non-zero on error 33 | */ 34 | int main(int ac, char **av) 35 | { 36 | if (ac < 2) 37 | { 38 | fprintf(stderr, "Usage: %s \n", av[0]); 39 | return (EXIT_FAILURE); 40 | } 41 | 42 | char *value = _getenv(av[1]); 43 | 44 | if (value == NULL) 45 | { 46 | printf("Environment variable '%s' not found\n", av[1]); 47 | return (EXIT_FAILURE); 48 | } 49 | 50 | printf("%s=%s\n", av[1], value); 51 | 52 | return (EXIT_SUCCESS); 53 | } 54 | -------------------------------------------------------------------------------- /test_files/test_builtins.c: -------------------------------------------------------------------------------- 1 | #include "../shell.h" 2 | #include 3 | 4 | int main(void) 5 | { 6 | char *dir = _getenv("PWD"); 7 | printf("Current directory: %s\n", dir); 8 | 9 | char *args[] = {"cd", "..", NULL}; 10 | shell_cd(args); 11 | 12 | char *args3[] = {"cd", "_test_", NULL}; 13 | shell_cd(args3); 14 | 15 | dir = _getenv("PWD"); 16 | printf("Current directory: %s\n", dir); 17 | 18 | args[0] = "setenv"; 19 | args[1] = "SHELL"; 20 | args[2] = "myshell"; 21 | args[3] = NULL; 22 | shell_setenv(args); 23 | 24 | /* Get the value of the environment variable */ 25 | char *value = getenv("SHELL"); 26 | if (value == NULL) 27 | { 28 | fprintf(stderr, "Failed to get environment variable\n"); 29 | exit(EXIT_FAILURE); 30 | } 31 | if (strcmp(value, "myshell") != 0) 32 | { 33 | fprintf(stderr, "Unexpected environment variable value: %s\n", value); 34 | exit(EXIT_FAILURE); 35 | } 36 | 37 | args[0] = "unsetenv"; 38 | args[1] = "SHELL"; 39 | args[2] = NULL; 40 | shell_unsetenv(args); 41 | 42 | /* Get the value of the environment variable again */ 43 | value = getenv("MYVAR"); 44 | if (value != NULL) 45 | { 46 | fprintf(stderr, "Environment variable was not unset\n"); 47 | exit(EXIT_FAILURE); 48 | } 49 | 50 | printf("All setenv and unsetenv tests passed\n"); 51 | 52 | args[0] = "exit"; 53 | args[1] = NULL; 54 | shell_exit(args); 55 | 56 | return (0); 57 | } 58 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/tok.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | /** 4 | * tokenize - tokenize a string 5 | * 6 | * Return: array of tokens. 7 | */ 8 | char **tokenize(char *str, const char *delim) 9 | { 10 | char *token; 11 | char **ret = NULL; 12 | int i = 0; 13 | 14 | token = strtok(str, delim); 15 | while (token) 16 | { 17 | ret = realloc(ret, sizeof(char *) * (i + 1)); 18 | if (ret == NULL) 19 | dprintf(2, "Error: realloc() failure\n"), exit(EXIT_FAILURE); 20 | 21 | ret[i] = malloc(strlen(token) + 1); 22 | if (!(ret[i])) 23 | dprintf(2, "Error: malloc() failure\n"), exit(EXIT_FAILURE); 24 | 25 | strcpy(ret[i], token); 26 | token = strtok(NULL, delim); 27 | i++; 28 | /*increase the size of the array*/ 29 | ret = realloc(ret, (i + 1) * sizeof(char *)); 30 | if (!ret) 31 | dprintf(2, "Error: realloc() failure\n"), exit(EXIT_FAILURE); 32 | } 33 | 34 | ret[i] = NULL; 35 | return (ret); 36 | } 37 | #if 0 38 | /** 39 | * main - entry point 40 | * 41 | * Return: EXIT_SUCCESS. 42 | */ 43 | int main(void) 44 | { 45 | char str[] = "raymond:kemboi\n"; 46 | char **arr = tokenize(str, ":"); 47 | int i; 48 | 49 | for (i = 0; arr[i]; i++) 50 | { 51 | if (arr[i + 1] == NULL) 52 | { 53 | printf("%s", arr[i]); 54 | } 55 | else 56 | puts(arr[i]); 57 | } 58 | for (i = 0; arr[i]; i++) 59 | free(arr[i]); 60 | free(arr); 61 | 62 | exit(EXIT_SUCCESS); 63 | } 64 | #endif 65 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/which/tok.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | /** 4 | * tokenize - tokenize a string 5 | * 6 | * Return: array of tokens. 7 | */ 8 | char **tokenize(char *str, const char *delim) 9 | { 10 | char *token; 11 | char **ret = NULL; 12 | int i = 0; 13 | 14 | token = strtok(str, delim); 15 | while (token) 16 | { 17 | ret = realloc(ret, sizeof(char *) * (i + 1)); 18 | if (ret == NULL) 19 | dprintf(2, "Error: realloc() failure\n"), exit(EXIT_FAILURE); 20 | 21 | ret[i] = malloc(strlen(token) + 1); 22 | if (!(ret[i])) 23 | dprintf(2, "Error: malloc() failure\n"), exit(EXIT_FAILURE); 24 | 25 | strcpy(ret[i], token); 26 | token = strtok(NULL, delim); 27 | i++; 28 | } 29 | 30 | /*increase the size of the array*/ 31 | ret = realloc(ret, (i + 1) * sizeof(char *)); 32 | if (!ret) 33 | dprintf(2, "Error: realloc() failure\n"), exit(EXIT_FAILURE); 34 | ret[i] = NULL; 35 | return (ret); 36 | } 37 | #if 0 38 | /** 39 | * main - entry point 40 | * 41 | * Return: EXIT_SUCCESS. 42 | */ 43 | int main(void) 44 | { 45 | char str[] = "raymond:kemboi\n"; 46 | char **arr = tokenize(str, ":"); 47 | int i; 48 | 49 | for (i = 0; arr[i]; i++) 50 | { 51 | if (arr[i + 1] == NULL) 52 | { 53 | printf("%s", arr[i]); 54 | } 55 | else 56 | puts(arr[i]); 57 | } 58 | for (i = 0; arr[i]; i++) 59 | free(arr[i]); 60 | free(arr); 61 | 62 | exit(EXIT_SUCCESS); 63 | } 64 | #endif 65 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/which3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int ac, char **av) 10 | { 11 | char *str, pathname[1024]; 12 | struct stat st; 13 | int i = 1, error = 0, idx, tmp, j; 14 | int abs_path; 15 | 16 | memset(pathname, 0, 1024); 17 | 18 | if (ac < 2) 19 | { 20 | dprintf(2, "Usage: %s ...\n", av[0]); 21 | return (1); 22 | } 23 | 24 | /* str = "/home/kemboiray/ALX-Local/simple_shell/shell_practice/0x00-shell/"; 25 | for (idx = 0; str[idx]; idx++) 26 | pathname[idx] = str[idx]; 27 | */ 28 | str = getcwd(NULL, 0); 29 | if (str == NULL) 30 | { 31 | perror("getcwd error"); 32 | return (1); 33 | } 34 | 35 | idx = strlen(str); 36 | for (j = 0; j < idx; j++) 37 | pathname[j] = str[j]; 38 | pathname[idx++] = '/'; 39 | 40 | while (av[i]) 41 | { 42 | tmp = idx; 43 | for (j = 0; (av[i])[j]; tmp++, j++) 44 | pathname[tmp] = (av[i])[j]; 45 | 46 | if (av[i][0] == '/') 47 | { 48 | abs_path = 1; 49 | puts("used abs"); 50 | } 51 | else 52 | { 53 | abs_path = 0; 54 | puts("not abs"); 55 | } 56 | 57 | if (stat(av[i], &st) == 0) 58 | puts(pathname); 59 | else 60 | error = 1; 61 | 62 | i++; 63 | } 64 | 65 | if (error == 1) 66 | dprintf(2, " "); 67 | 68 | free(str); 69 | return (error); 70 | } 71 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/builtins_01.c_bac: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * shell_exit - exits the shell 5 | * @args: arguments passed to the function 6 | * 7 | * Return: 0 on success, -1 on failure 8 | */ 9 | int shell_exit(char **args) 10 | { 11 | int status = 0; 12 | 13 | if (args && args[1]) 14 | { 15 | status = atoi(args[1]); 16 | if (status == 0 && strcmp(args[1], "0") != 0) 17 | { 18 | _puterror("Illegal number: "); 19 | _puterror(args[1]); 20 | _puterror("\n"); 21 | return (-1); 22 | } 23 | } 24 | 25 | free(args); 26 | exit(status); 27 | } 28 | 29 | /** 30 | * shell_cd - changes the current directory 31 | * @args: arguments passed to the function 32 | * 33 | * Return: 0 on success, -1 on failure 34 | */ 35 | int shell_cd(char **args) 36 | { 37 | char *home = getenv("HOME"); 38 | char *path = args[1]; 39 | 40 | if (!path) 41 | { 42 | if (home) 43 | path = home; 44 | else 45 | return (-1); 46 | } 47 | 48 | if (chdir(path) == -1) 49 | { 50 | _puterror("cd: can't cd to "); 51 | _puterror(path); 52 | _puterror("\n"); 53 | return (-1); 54 | } 55 | 56 | return (0); 57 | } 58 | 59 | /** 60 | * shell_env - prints the current environment 61 | * @args: arguments passed to the function 62 | * 63 | * Return: 0 on success, -1 on failure 64 | */ 65 | int shell_env(char **args) 66 | { 67 | int i; 68 | 69 | for (i = 0; environ[i] != NULL; i++) 70 | _puts(environ[i]); 71 | 72 | return (0); 73 | } 74 | -------------------------------------------------------------------------------- /parser.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * tokenize - parsing user input into arguments 5 | * by splits an array string into tokens using a delimiter. 6 | * @str: the string to be tokenized. 7 | * @delim: the delimiter used to split the string. 8 | * 9 | * Return: an array of pointers to the tokens, 10 | * or NULL if an error occurs. 11 | */ 12 | char **tokenize(char *str, const char *delim) 13 | { 14 | char *token = NULL; 15 | char **ret = NULL; 16 | int i = 0; 17 | 18 | token = strtok(str, delim); 19 | while (token) 20 | { 21 | ret = realloc(ret, sizeof(char *) * (i + 1)); 22 | if (ret == NULL) 23 | return (NULL); 24 | 25 | ret[i] = malloc(_strlen(token) + 1); 26 | if (!(ret[i])) 27 | return (NULL); 28 | 29 | _strcpy(ret[i], token); 30 | token = strtok(NULL, delim); 31 | i++; 32 | } 33 | /*increase the size of the array*/ 34 | ret = realloc(ret, (i + 1) * sizeof(char *)); 35 | if (!ret) 36 | return (NULL); 37 | 38 | ret[i] = NULL; 39 | return (ret); 40 | } 41 | 42 | /** 43 | * tokenize_input - splits a user input string into tokens with tokenize(). 44 | * @input: the user input string to be tokenized 45 | * 46 | * Return: an array of pointers to the tokens, or NULL if an error occurs 47 | */ 48 | char **tokenize_input(char *input) 49 | { 50 | char **tokens = NULL; 51 | char *tmp = NULL; 52 | 53 | tmp = _strdup(input); 54 | if (tmp == NULL) 55 | { 56 | _puts("Memory allocation error\n"); 57 | exit(EXIT_FAILURE); 58 | } 59 | 60 | tokens = tokenize(tmp, " \t\r\n\a"); 61 | free(tmp); 62 | 63 | return (tokens); 64 | } 65 | -------------------------------------------------------------------------------- /shell_practice/sprintf/sprintf.txt: -------------------------------------------------------------------------------- 1 | int _sprintf(char *str, const char *format, ...) 2 | { 3 | va_list args; 4 | int i = 0; 5 | 6 | va_start(args, format); 7 | while (*format) 8 | { 9 | /* If the format specifier is encountered*/ 10 | if (*format == '%') 11 | { 12 | format++; 13 | switch (*format) 14 | { 15 | case 'd': 16 | { 17 | int arg = va_arg(args, int); 18 | int j = 0, k = arg; 19 | 20 | /* Reverse the number*/ 21 | while (k) 22 | { 23 | str[i++] = (k % 10) + '0'; 24 | k /= 10; 25 | j++; 26 | } 27 | 28 | /* Reverse the string*/ 29 | for (j = j - 1; j >= 0; j--, i++) 30 | str[i] = str[i - j - 1]; 31 | break; 32 | } 33 | 34 | case 's': 35 | { 36 | char *arg = va_arg(args, char *); 37 | int j = 0; 38 | 39 | /* Copy the string*/ 40 | while (arg[j] != '\0') 41 | str[i++] = arg[j++]; 42 | break; 43 | } 44 | } 45 | } 46 | else 47 | str[i++] = *format; 48 | 49 | format++; 50 | } 51 | va_end(args); 52 | 53 | /* Add null terminator */ 54 | str[i] = '\0'; 55 | 56 | return (i); 57 | } 58 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/shell.h: -------------------------------------------------------------------------------- 1 | #ifndef SHELL_H 2 | #define SHELL_H 3 | 4 | /* Libraries */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /* Global Variables */ 15 | extern char **environ; 16 | 17 | /* Structs */ 18 | /** 19 | * struct path_s - linked list of PATH directories 20 | * @dir: directory in PATH 21 | * @next: pointer to next node 22 | */ 23 | typedef struct path_s 24 | { 25 | char *dir; 26 | struct path_s *next; 27 | } path_t; 28 | 29 | /* Function Prototypes */ 30 | /* prompt.c */ 31 | void print_prompt(void); 32 | 33 | /* main.c */ 34 | char *read_line(void); 35 | char **parse_line(char *line); 36 | int execute(char **args, char *path); 37 | 38 | /* builtins.c */ 39 | int shell_exit(char **args); 40 | int shell_cd(char **args); 41 | /* int shell_env(char **args); */ 42 | int _env(char **env); 43 | 44 | /* path.c */ 45 | char *get_path(char **env); 46 | void free_path_list(path_t *head); 47 | path_t *path_list(char *path); 48 | 49 | /* _getenv.c*/ 50 | char *_getenv(char *name); 51 | 52 | /* execute.c */ 53 | int execute(char **args, char *path); 54 | int check_for_builtin(char **args); 55 | char **tokenize(char *input, const char *delimiter); 56 | void free_tokens(char **tokens); 57 | 58 | /* helpers.c */ 59 | int _putchar(char c); 60 | void _puts(char *str); 61 | void _puterror(char *str); 62 | int _strlen(char *s); 63 | char *_strcpy(char *dest, char *src); 64 | char *_strcat(char *dest, char *src); 65 | char *_strdup(char *str); 66 | int _strcmp(char *s1, char *s2); 67 | int _atoi(char *s); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/error2.c_bac: -------------------------------------------------------------------------------- 1 | #define BUFFER_SIZE 1024 2 | 3 | /** 4 | * _putstring - writes a string to standard output 5 | * @str: the string to write 6 | */ 7 | void _putstring(char *str) 8 | { 9 | static char buffer[BUFFER_SIZE]; 10 | static int pos = 0; 11 | int len = _strlen(str); 12 | 13 | if (len > BUFFER_SIZE - pos) 14 | { 15 | write(STDOUT_FILENO, buffer, pos); 16 | pos = 0; 17 | } 18 | _strcpy(buffer + pos, str); 19 | pos += len; 20 | } 21 | 22 | /** 23 | * _flush - flushes the output buffer 24 | */ 25 | void _flush() 26 | { 27 | if (pos > 0) 28 | { 29 | write(STDOUT_FILENO, buffer, pos); 30 | pos = 0; 31 | } 32 | } 33 | 34 | 35 | /** 36 | * _puterror - prints an error message to standard error 37 | * @str: the error message to print 38 | * @func_name: the name of the function where the error occurred 39 | * @line_no: the line number where the error occurred 40 | */ 41 | void _puterror(char *str, char *func_name, int line_no) 42 | { 43 | char *line_no_str; 44 | char *err_msg; 45 | 46 | err_msg = "Error: "; 47 | _putstring(STDERR_FILENO, err_msg); 48 | if (func_name != NULL) 49 | { 50 | _putstring(STDERR_FILENO, func_name); 51 | _putstring(STDERR_FILENO, ": "); 52 | } 53 | if (line_no > 0) 54 | { 55 | line_no_str = int_to_str(line_no); 56 | _putstring(STDERR_FILENO, "line "); 57 | _putstring(STDERR_FILENO, line_no_str); 58 | _putstring(STDERR_FILENO, ": "); 59 | free(line_no_str); 60 | } 61 | _putstring(STDERR_FILENO, str); 62 | _flush(STDERR_FILENO); 63 | } 64 | 65 | /** 66 | * _puts - prints a string to standard output 67 | * @str: the string to print 68 | */ 69 | void _puts(char *str) 70 | { 71 | _putstring(str); 72 | _flush(); 73 | } 74 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/_setenv.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "pathlist.c" 3 | #include "_getenvfull.c" 4 | 5 | /** 6 | * _setenv - custom implementation of setenv() 7 | * @name: variable name 8 | * @value: string value with which `name` may be set 9 | * @overwrite: integer value indicating whether an existing value string 10 | * should be overwritten 11 | * 12 | * Return: 0 (success), or -1 (failure). 13 | */ 14 | int _setenv(const char *name, const char *value, int overwrite) 15 | { 16 | char *ptr = _getenvfull(name); 17 | path_list *head = build_list(environ); 18 | path_list *temp = head; 19 | 20 | if (ptr) 21 | { 22 | if (overwrite == 0) 23 | return (0); 24 | else 25 | { 26 | while(1) 27 | { 28 | if (!(strcmp(ptr, temp->dir_node))) 29 | { 30 | temp->dir_node = calloc(strlen(value) + 1, sizeof(char)); 31 | if (!(temp->dir_node)) 32 | { 33 | dprintf(2, "calloc() failure\n"); 34 | return (-1); 35 | } 36 | temp->dir_node = (char *)value; 37 | break; 38 | } 39 | temp = temp->next; 40 | } 41 | } 42 | } 43 | else 44 | { 45 | while(temp) 46 | temp = temp->next; 47 | temp = malloc(sizeof(path_list)); 48 | if (!(temp)) 49 | { 50 | dprintf(2, "malloc() failure\n"); 51 | return (-1); 52 | } 53 | temp->dir_node = (char *)value; 54 | temp->next = NULL; 55 | } 56 | return (0); 57 | } 58 | 59 | /** 60 | * main - check code 61 | * 62 | * Return: 0. 63 | */ 64 | int main(void) 65 | { 66 | printf("Before: %s\n", _getenvfull("USER")); 67 | _setenv("USER", "raymond", 1); 68 | printf("After: %s\n", _getenvfull("USER")); 69 | _setenv("AAHAV", "meaningless", 1); 70 | // printf("%s\n", _getenvfull("AAHAV")); 71 | return (0); 72 | } 73 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/0-simpleShell.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define MAX_COMMAND_LENGTH 100 8 | 9 | int main() { 10 | char* command = NULL; 11 | size_t command_size = 0; 12 | 13 | while (1) { 14 | printf("#cisfun$ "); 15 | if (getline(&command, &command_size, stdin) == -1) { 16 | break; 17 | } 18 | 19 | // Remove the trailing newline character from the command string 20 | command[strcspn(command, "\n")] = '\0'; 21 | 22 | pid_t pid = fork(); 23 | if (pid == -1) { 24 | perror("fork"); 25 | exit(EXIT_FAILURE); 26 | } else if (pid == 0) { 27 | // Child process 28 | 29 | // Parse the command and arguments 30 | char* tokens[MAX_COMMAND_LENGTH]; 31 | char* token = strtok(command, " "); 32 | int i = 0; 33 | while (token != NULL) { 34 | tokens[i++] = token; 35 | token = strtok(NULL, " "); 36 | } 37 | tokens[i] = NULL; // Set the last argument to NULL 38 | 39 | // Execute the command with its full path 40 | if (execv(tokens[0], tokens) == -1) { 41 | perror("execv"); 42 | exit(EXIT_FAILURE); 43 | } 44 | } else { 45 | // Parent process 46 | 47 | // Wait for the child process to complete 48 | if (wait(NULL) == -1) { 49 | perror("wait"); 50 | exit(EXIT_FAILURE); 51 | } 52 | } 53 | } 54 | 55 | free(command); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /shell_practice/raymond/shell.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * main - implements a simple shell 5 | * @ac: argument count 6 | * @av: argument vector 7 | * @ev: environment 8 | * 9 | * Return: EXIT_SUCCESS. 10 | */ 11 | int main(int ac __attribute__((unused)), char **av, char **ev) 12 | { 13 | char *arg = NULL; 14 | char **argv = NULL; 15 | char temp[120]; 16 | char bin[6] = "/bin/"; 17 | size_t len = 0; 18 | ssize_t nread; 19 | pid_t id; 20 | int status, i; 21 | 22 | _memset(temp, 0, 120); 23 | _puts("$ "); 24 | while ((nread = getline(&arg, &len, stdin)) != -1) 25 | { 26 | if (_strcmp(arg, "\n") == 0) 27 | { 28 | free(arg); 29 | arg = NULL; 30 | _puts("$ "); 31 | continue; 32 | } 33 | if (_strcmp(arg, "exit\n") == 0) 34 | free(arg), exit(EXIT_SUCCESS); 35 | arg[nread - 1] = '\0'; 36 | if (arg[0] != '/') 37 | { 38 | _strcpy(temp, arg); 39 | arg = realloc(arg, _strlen(temp) + 6); 40 | _memset(arg, 0, _strlen(arg) + 1); 41 | arg = _strcat(bin, temp); 42 | } 43 | argv = tokenize(arg, " "); 44 | if (!argv) 45 | { 46 | free(arg); 47 | dprintf(2, "Error parsing commands\n"); 48 | _puts("$ "); 49 | continue; 50 | } 51 | id = fork(); 52 | if (id == -1) 53 | perror(av[0]); 54 | if (id == 0) 55 | { 56 | /* if (_strcmp(arg, "env") == 0) 57 | printenviron(ev), exit(EXIT_SUCCESS); 58 | */ if (execve(argv[0], argv, ev) == -1) 59 | perror(av[0]), exit(EXIT_FAILURE); 60 | } 61 | else 62 | { 63 | wait(&status); 64 | for (i = 0; argv[i]; i++) 65 | { 66 | free(argv[i]); 67 | argv[i] = NULL; 68 | } 69 | free(argv); 70 | free(arg); 71 | argv = NULL; 72 | arg = NULL; 73 | _puts("$ "); 74 | } 75 | } 76 | free(arg); 77 | _putchar('\n'); 78 | exit(EXIT_SUCCESS); 79 | } 80 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/path.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * get_path - get the value of the PATH environment variable 5 | * @env: the environment variables 6 | * 7 | * Return: a pointer to the PATH value, or NULL if it is not found 8 | */ 9 | char *get_path(char **env) 10 | { 11 | int i; 12 | 13 | for (i = 0; env[i] != NULL; i++) 14 | { 15 | if (strncmp(env[i], "PATH=", 5) == 0) 16 | return (env[i] + 5); 17 | } 18 | 19 | return (NULL); 20 | } 21 | 22 | /** 23 | * free_path_list - frees a linked list of path_t nodes 24 | * @head: a pointer to the head of the linked list 25 | */ 26 | void free_path_list(path_t *head) 27 | { 28 | path_t *tmp; 29 | 30 | while (head != NULL) 31 | { 32 | tmp = head; 33 | head = head->next; 34 | free(tmp->dir); 35 | free(tmp); 36 | } 37 | } 38 | 39 | /** 40 | * path_list - creates a linked list of directories from a PATH string 41 | * @path: the PATH string 42 | * 43 | * Return: a pointer to the head of the linked list 44 | */ 45 | path_t *path_list(char *path) 46 | { 47 | path_t *head = NULL, *new = NULL, *tmp = NULL; 48 | char *token; 49 | 50 | token = strtok(path, ":"); 51 | while (token != NULL) 52 | { 53 | new = malloc(sizeof(path_t)); 54 | if (new == NULL) 55 | { 56 | _puterror("Memory allocation error\n"); 57 | free_path_list(head); 58 | return (NULL); 59 | } 60 | new->dir = _strdup(token); 61 | if (new->dir == NULL) 62 | { 63 | _puterror("Memory allocation error\n"); 64 | free(new); 65 | free_path_list(head); 66 | return (NULL); 67 | } 68 | new->next = NULL; 69 | 70 | if (head == NULL) 71 | head = new; 72 | else 73 | { 74 | tmp = head; 75 | while (tmp->next != NULL) 76 | tmp = tmp->next; 77 | tmp->next = new; 78 | } 79 | 80 | token = strtok(NULL, ":"); 81 | } 82 | 83 | return (head); 84 | } 85 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/which/which.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #define BUFFSIZE 4096 3 | 4 | /** 5 | * main - locates a command 6 | * @ac: arg count 7 | * @av: arg vector 8 | * 9 | * Return: 0 (success), 1 (failure). 10 | */ 11 | int main(int ac, char **av) 12 | { 13 | struct stat st; 14 | int stat_ret, i, j, k, extat = 0; 15 | char buf[BUFFSIZE], *temp, **tempath, **path; 16 | 17 | if (ac < 2) 18 | dprintf(2, "Usage: %s ...\n", av[0]), exit(1); 19 | temp = _getenv("PATH"); 20 | if (!temp) 21 | dprintf(2, "PATH not found!\n"), exit(1); 22 | path = tokenize(temp, ":"); 23 | if (!path) 24 | dprintf(2, "Memory allocation error!\n"), exit(1); 25 | 26 | for (i = 1; av[i]; i++) 27 | { 28 | if (av[i][0] == '/') 29 | { 30 | if (stat(av[i], &st) == -1) 31 | { 32 | extat = 1; 33 | continue; 34 | } 35 | memset(buf, 0, BUFFSIZE); 36 | strcpy(buf, av[i]); 37 | tempath = tokenize(buf, "/"); 38 | if (!tempath) 39 | { 40 | cleaner(path); 41 | dprintf(2, "Memory allocation error!\n"), exit(1); 42 | } 43 | for (k = 0; tempath[k]; k++) 44 | ; 45 | for(j = 0; path[j]; j++) 46 | { 47 | memset(buf, 0, BUFFSIZE); 48 | strcpy(buf, path[j]); 49 | strcat(buf, "/"); 50 | strcat(buf, tempath[k - 1]); 51 | stat_ret = stat(buf, &st); 52 | if (stat_ret == 0) 53 | { 54 | puts(buf); 55 | break; 56 | } 57 | } 58 | if (stat_ret == -1) 59 | extat = 1; 60 | cleaner(tempath); 61 | } 62 | else 63 | { 64 | for (j = 0; path[j]; j++) 65 | { 66 | memset(buf, 0, BUFFSIZE); 67 | strcpy(buf, path[j]); 68 | strcat(buf, "/"); 69 | strcat(buf, av[i]); 70 | stat_ret = stat(buf, &st); 71 | if (stat_ret == 0) 72 | { 73 | puts(buf); 74 | break; 75 | } 76 | } 77 | if (stat_ret == -1) 78 | extat = 1; 79 | } 80 | } 81 | cleaner(path); 82 | exit(extat); 83 | } 84 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/tok3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define BUFFSIZE 1024 7 | 8 | /** 9 | * tokenize - tokenize a string into words 10 | * 11 | * Return: array of word pointers 12 | */ 13 | char **tokenize(void) 14 | { 15 | char str[BUFFSIZE]; 16 | char *token; 17 | char *s = " "; 18 | char **ret = NULL; 19 | int i = 0; 20 | 21 | if (fgets(str, BUFFSIZE, stdin) == NULL) { 22 | return NULL; 23 | } 24 | if (str[strlen(str) - 1] == '\n') { 25 | str[strlen(str) - 1] = '\0'; 26 | } 27 | token = strtok(str, s); 28 | while (token != NULL) 29 | { 30 | ret = realloc(ret, sizeof(char *) * (i + 1)); 31 | if (ret == NULL) 32 | { 33 | dprintf(2, "Error: realloc() failure\n"); 34 | exit(EXIT_FAILURE); 35 | } 36 | ret[i] = malloc(strlen(token) + 1); 37 | if (ret[i] == NULL) 38 | { 39 | dprintf(2, "Error: malloc() failure\n"); 40 | exit(EXIT_FAILURE); 41 | } 42 | strcpy(ret[i], token); 43 | token = strtok(NULL, s); 44 | i++; 45 | } 46 | ret = realloc(ret, sizeof(char *) * (i + 1)); 47 | if (ret == NULL) 48 | { 49 | dprintf(2, "Error: realloc() failure\n"); 50 | exit(EXIT_FAILURE); 51 | } 52 | ret[i] = NULL; 53 | return ret; 54 | } 55 | 56 | /** 57 | * main - entry point 58 | * 59 | * Return: EXIT_SUCCESS 60 | */ 61 | int main(void) 62 | { 63 | char **arr = tokenize(); 64 | int i; 65 | 66 | if (arr == NULL) { 67 | fprintf(stderr, "Error: fgets() failure\n"); 68 | exit(EXIT_FAILURE); 69 | } 70 | 71 | for (i = 0; arr[i] != NULL; i++) 72 | { 73 | printf("%s\n", arr[i]); 74 | free(arr[i]); 75 | } 76 | free(arr); 77 | return EXIT_SUCCESS; 78 | } 79 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/tok2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #define BUFFSIZE 1024 6 | 7 | /** 8 | * tokenize - tokenize a string 9 | * 10 | * Return: array of tokens. 11 | */ 12 | char **tokenize() 13 | { 14 | char str[BUFFSIZE]; 15 | char *token; 16 | char *s = " "; 17 | char **ret; 18 | int i = 0, j; 19 | 20 | fgets(str, BUFFSIZE, stdin); // read input from stdin 21 | 22 | token = strtok(str, s); // get the first token 23 | 24 | /* allocate memory for the array of tokens */ 25 | ret = malloc(sizeof(char *)); 26 | if (!ret) 27 | { 28 | dprintf(2, "Error: malloc() failure\n"); 29 | exit(EXIT_FAILURE); 30 | } 31 | 32 | while (token) 33 | { 34 | ret[i] = malloc(strlen(token) + 1); // allocate memory for each token 35 | if (!ret[i]) 36 | { 37 | dprintf(2, "Error: malloc() failure\n"); 38 | exit(EXIT_FAILURE); 39 | } 40 | for (j = 0; token[j]; j++) 41 | ret[i][j] = token[j]; // copy the characters of the token into the array 42 | token = strtok(NULL, s); // get the next token 43 | i++; 44 | ret = realloc(ret, (i + 1) * sizeof(char *)); // increase the size of the array 45 | if (!ret) 46 | { 47 | dprintf(2, "Error: realloc() failure\n"); 48 | exit(EXIT_FAILURE); 49 | } 50 | } 51 | 52 | ret[i] = NULL; // set the last element to NULL to mark the end of the array 53 | 54 | return ret; 55 | } 56 | 57 | /** 58 | * main - entry point 59 | * 60 | * Return: EXIT_SUCCESS. 61 | */ 62 | int main(void) 63 | { 64 | char **arr = tokenize(); 65 | int i; 66 | 67 | for (i = 0; arr[i]; i++) 68 | { 69 | if (arr[i + 1] == NULL) 70 | printf("%s", arr[i]); // print the last element without a newline 71 | else 72 | puts(arr[i]); // print the element with a newline 73 | } 74 | 75 | /* free the memory allocated for each token and for the array */ 76 | for (i = 0; arr[i]; i++) 77 | free(arr[i]); 78 | free(arr); 79 | 80 | exit(EXIT_SUCCESS); 81 | } 82 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/pathlist.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "tok.c" 3 | #include "_getenv.c" 4 | 5 | /** 6 | * path_ptrs - returns an array of directories in $PATH 7 | * 8 | * Return: see description. 9 | */ 10 | char **path_ptrs(void) 11 | { 12 | char *path = _getenv("PATH"); 13 | char *str = path; 14 | char **dir = tokenize(str, ":"); 15 | unsigned int i; 16 | 17 | if (!(path)) 18 | dprintf(2, "$PATH not found!\n"), exit(EXIT_FAILURE); 19 | 20 | return (dir); 21 | } 22 | 23 | /** build_list - builds a linked list of directories in $PATH. 24 | * 25 | * Return: pointer to beginning of list. 26 | */ 27 | path_list *build_list(char **ptrs) 28 | { 29 | int i; 30 | path_list *head; 31 | path_list *temp = NULL; 32 | 33 | /* Whiteboarding */ 34 | if (!(head = malloc(sizeof(path_list)))) 35 | dprintf(2, "malloc() failure\n"), exit(EXIT_FAILURE); 36 | head->dir_node = ptrs[0]; 37 | head->next = NULL; 38 | temp = head; 39 | for (i = 1; ptrs[i]; i++) 40 | { 41 | if (!(temp->next = malloc(sizeof(path_list)))) 42 | dprintf(2, "malloc() failure\n"), exit(EXIT_FAILURE); 43 | temp = temp->next; 44 | temp->dir_node = ptrs[i]; 45 | temp->next = NULL; 46 | } 47 | return (head); 48 | } 49 | 50 | /** 51 | * free_list - frees a singly-linked list 52 | * @head: pointer to first node 53 | * @tok: switch to indicate whether tokenize() was used (1) or not (0) 54 | * 55 | * Return: void. 56 | */ 57 | void free_list(path_list *head, int tok) 58 | { 59 | path_list *temp; 60 | // char **ptr; 61 | int i; 62 | 63 | // ptr = &(head->dir_node); 64 | while (head) 65 | { 66 | temp = head->next; 67 | if (tok) 68 | free(head->dir_node); 69 | free(head); 70 | head = temp; 71 | } 72 | // free(ptr); 73 | } 74 | 75 | #if 0 76 | /** 77 | * main - print linked list 78 | * 79 | * Return: 0. 80 | */ 81 | int main(void) 82 | { 83 | char **ptr = path_ptrs(); 84 | path_list *head = build_list(ptr); 85 | path_list *temp = head; 86 | while(temp) 87 | { 88 | puts(temp->dir_node); 89 | temp = temp->next; 90 | } 91 | free_list(head, 1); 92 | return 0; 93 | } 94 | #endif 95 | -------------------------------------------------------------------------------- /simple_shell.1.md: -------------------------------------------------------------------------------- 1 | % simple_shell(1) 2 | 3 | # NAME 4 | 5 | simple_shell - a simple UNIX command-line interpreter, also known as a shell 6 | 7 | # SYNOPSIS 8 | 9 | **simple_shell** [**command**] 10 | 11 | # DESCRIPTION 12 | 13 | The **simple_shell** is a command-line interpreter for UNIX-based operating systems. It is capable of reading commands from standard input, parsing them, and executing them. 14 | 15 | # OPTIONS 16 | 17 | The **simple_shell** does not accept any command-line options. 18 | 19 | # COMMANDS 20 | 21 | The **simple_shell** accepts the following commands: 22 | 23 | - cd [DIRECTORY]: changes the current working directory to DIRECTORY 24 | - exit [STATUS]: exits the shell with a status code of STATUS (default is 0) 25 | - help: displays help information for the shell 26 | - env: prints the current environment variables 27 | - setenv [NAME] [VALUE]: sets the environment variable NAME to VALUE 28 | - unsetenv [NAME]: unsets the environment variable NAME 29 | 30 | # ENVIRONMENT 31 | 32 | The **simple_shell** program does not set or use any environment variables. 33 | 34 | # EXIT STATUS 35 | 36 | The **simple_shell** program returns the following exit codes: 37 | 38 | - 0: successful termination 39 | - 1: general error 40 | - 2: incorrect usage 41 | 42 | # EXAMPLES 43 | 44 | To change the current working directory to /usr/local/bin: 45 | 46 | $ cd /usr/local/bin 47 | 48 | 49 | To exit the shell with a status code of 1: 50 | 51 | $ exit 1 52 | 53 | To print help information for the shell: 54 | 55 | $ help 56 | 57 | To print the current environment variables: 58 | 59 | $ env 60 | 61 | To set an environment variable: 62 | 63 | $ setenv MY_VAR my_value 64 | 65 | To unset an environment variable: 66 | 67 | $ unsetenv MY_VAR 68 | 69 | # AUTHORS 70 | 71 | This project was created by FourtyThree43 and Kemboiray as part of the curriculum for Alx Software Engineering. 72 | 73 | # REPORTING BUGS 74 | 75 | Report any bugs or issues to gihub @fourtythree43.com or @kemboiray. 76 | 77 | # COPYRIGHT 78 | 79 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU 80 | -------------------------------------------------------------------------------- /utils_funcs2.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _strcpy - copies a string 5 | * @dest: the destination 6 | * @src: the source 7 | * 8 | * Return: pointer to destination 9 | */ 10 | char *_strcpy(char *dest, char *src) 11 | { 12 | int i = 0; 13 | 14 | if (dest == src || src == 0) 15 | return (dest); 16 | while (src[i]) 17 | { 18 | dest[i] = src[i]; 19 | i++; 20 | } 21 | dest[i] = 0; 22 | return (dest); 23 | } 24 | 25 | /** 26 | * _strcat - concatenates two strings 27 | * @dest: the destination buffer 28 | * @src: the source buffer 29 | * 30 | * Return: pointer to destination buffer 31 | */ 32 | char *_strcat(char *dest, const char *src) 33 | { 34 | char *ret = dest; 35 | 36 | while (*dest) 37 | dest++; 38 | while (*src) 39 | *dest++ = *src++; 40 | *dest = *src; 41 | return (ret); 42 | } 43 | 44 | /** 45 | * _strdup - duplicates a string 46 | * @str: the string to duplicate 47 | * 48 | * Return: pointer to the duplicated string 49 | */ 50 | char *_strdup(const char *str) 51 | { 52 | int length = 0; 53 | char *ret; 54 | 55 | if (str == NULL) 56 | return (NULL); 57 | while (*str++) 58 | length++; 59 | ret = malloc(sizeof(char) * (length + 1)); 60 | if (!ret) 61 | return (NULL); 62 | for (length++; length--;) 63 | ret[length] = *--str; 64 | return (ret); 65 | } 66 | 67 | /** 68 | *_putchar - writes the character c to stdout 69 | * @c: The character to print 70 | * Return: On success 1. 71 | * On error, -1 is returned, and errno is set appropriately. 72 | */ 73 | int _putchar(char c) 74 | { 75 | return (write(1, &c, 1)); 76 | } 77 | 78 | /** 79 | * _strspn - a function that gets the 80 | * length of a prefix substring 81 | * 82 | * @s: pointer to string input 83 | * @accept: substring prefix to look for 84 | * 85 | * Return: the number of bytes in the initial segment 86 | */ 87 | unsigned int _strspn(char *s, char *accept) 88 | { 89 | unsigned int i, j; 90 | 91 | for (i = 0; s[i]; i++) 92 | { 93 | for (j = 0; accept[j]; j++) 94 | { 95 | if (s[i] == accept[j]) 96 | break; 97 | } 98 | if (!accept[j]) 99 | return (i); 100 | } 101 | 102 | return (i); 103 | } 104 | -------------------------------------------------------------------------------- /shell.h: -------------------------------------------------------------------------------- 1 | #ifndef _SHELL_H_ 2 | #define _SHELL_H_ 3 | #define _GNU_SOURCE 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /*macros*/ 19 | #define PATH_MAX_LENGTH 4096 20 | #define PATH_SEPARATOR ":" 21 | #define PROMPT "$ " 22 | #define MAX_TOKENS 1024 23 | #define BUFFER_SIZE 1024 24 | 25 | /* prompt.c */ 26 | void prompt(void); 27 | 28 | /* get_input.c */ 29 | char *get_input(void); 30 | void free_last_input(void); 31 | /* get_line.c*/ 32 | void *get_line(void); 33 | 34 | /* built-in funcs */ 35 | int check_for_builtin(char **args); 36 | int execute_buitlin(char *cmd, char **args); 37 | void shell_help(void); 38 | void shell_exit(char **args); 39 | void shell_cd(char **args); 40 | int shell_setenv(char **args); 41 | int shell_unsetenv(char **args); 42 | int shell_env(void); 43 | int shell_clear(char **args); 44 | 45 | /* signal_handler.c */ 46 | void handle_sigint(int sig); 47 | void handle_sigquit(int sig); 48 | void handle_sigstp(int sig); 49 | 50 | /* execute.c */ 51 | int execute(char **args); 52 | 53 | /* parser.c */ 54 | char **tokenize(char *str, const char *delim); 55 | char **tokenize_input(char *input); 56 | 57 | /* get_env.c */ 58 | char *_getenv(const char *name); 59 | 60 | /* get_path.c */ 61 | char *get_path(void); 62 | 63 | /* find_in_path.c */ 64 | char *find_in_path(char *command); 65 | 66 | /* free.c */ 67 | void free_error(char **argv, char *arg); 68 | void free_tokens(char **ptr); 69 | void free_path(void); 70 | 71 | /* error.c */ 72 | void _puts(char *str); 73 | void _puterror(char *err); 74 | 75 | /* utils_funcs1.c */ 76 | int _strlen(const char *); 77 | int _strcmp(const char *s1, const char *s2); 78 | int _strncmp(const char *s1, const char *s2, size_t n); 79 | char *_strstr(char *haystack, char *needle); 80 | char *_strchr(char *s, char c); 81 | 82 | /* utils_funcs2.c */ 83 | char *_strcpy(char *, char *); 84 | char *_strcat(char *, const char *); 85 | char *_strdup(const char *); 86 | int _putchar(char); 87 | unsigned int _strspn(char *s, char *accept); 88 | 89 | /* utils_funcs3.c */ 90 | int _atoi(const char *str); 91 | char *_memset(char *, char, unsigned int); 92 | char *_memcpy(char *dest, char *src, unsigned int n); 93 | void *_realloc(void *, unsigned int, unsigned int); 94 | void *_calloc(unsigned int nmemb, unsigned int size); 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/README.md: -------------------------------------------------------------------------------- 1 | # Simple Shell Project 2 | 3 | This is a simple shell project that was developed as part of a course. 4 | 5 | ## Project Structure 6 | 7 | The project is organized as follows: 8 | 9 | ``` 10 | . 11 | ├── AUTHORS 12 | ├── README.md 13 | ├── simple_shell.1 (man page) 14 | ├── shell.h 15 | ├── main.c 16 | ├── built_ins.c 17 | │ ├── shell_exit 18 | │ ├── shell_cd 19 | │ └── shell_env 20 | ├── error_handling 21 | │ ├── error_handling.c 22 | │ ├── exit.c 23 | │ └── ... 24 | ├── helpers 25 | │ ├── _strtok.c 26 | │ ├── _strdup.c 27 | │ └── ... 28 | └── execute 29 | ├── execute.c 30 | ├── fork_and_execute.c 31 | └── ... 32 | ``` 33 | 34 | `AUTHORS` file lists the contributors to the project. 35 | 36 | `README.md` file you are currently reading is a brief overview of the project. 37 | 38 | `man_1_simple_shell` file is the man page for the shell. 39 | 40 | `shell.h`: a header file that includes all the necessary libraries, function prototypes, and global variables. 41 | 42 | `main.c`: the main file that contains the loop for getting the user input, parsing the input, and executing the command. 43 | 44 | `prompt.c`: a file that handles the prompt display for the shell. 45 | 46 | `helpers.c`: a file that contains helper functions for the shell, such as string manipulation functions and functions for printing error messages. 47 | 48 | `builtins.c`: a file that contains the implementations of the built-in commands (cd, exit, env). 49 | 50 | `path.c`: a file that contains functions for handling the PATH environment variable and searching for executables in the directories listed in PATH. 51 | 52 | `execute.c`: a file that contains the functions for executing the non-built-in commands. 53 | 54 | `Makefile`: a file that specifies the compilation rules for the shell. 55 | 56 | 57 | ## Usage 58 | 59 | To use the simple shell, compile the files using `gcc -Wall -Werror -Wextra -pedantic *.c -o hsh`. Then, run the shell using `./hsh`. 60 | 61 | ## Man Page. 62 | 63 | To generate a man page for the `simple_shell`, you can use the `ronn` utility. `ronn` allows you to write man pages in Markdown format and then convert them to man page format. 64 | 65 | Once you have created the `simple_shell.1.md` file, run the following command to generate the man page: 66 | 67 | `ronn simple_shell.1.md` 68 | 69 | This will create a new file called `simple_shell.1`. You can view the man page by running the following command: 70 | 71 | `man ./simple_shell.1` 72 | 73 | ## License 74 | 75 | This project is licensed under the MIT License - see the LICENSE file for details. 76 | 77 | -------------------------------------------------------------------------------- /shell_practice/raymond/string.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _strlen - returns the length of a string 5 | * @s: the string whose length to check 6 | * 7 | * Return: integer length of string 8 | */ 9 | int _strlen(char *s) 10 | { 11 | int i = 0; 12 | 13 | if (!s) 14 | return (0); 15 | 16 | while (*s++) 17 | i++; 18 | return (i); 19 | } 20 | 21 | /** 22 | * _strcmp - performs lexicogarphic comparison of two strangs. 23 | * @s1: the first strang 24 | * @s2: the second strang 25 | * 26 | * Return: negative if s1 < s2, positive if s1 > s2, zero if s1 == s2 27 | */ 28 | int _strcmp(char *s1, char *s2) 29 | { 30 | while (*s1 && *s2) 31 | { 32 | if (*s1 != *s2) 33 | return (*s1 - *s2); 34 | s1++; 35 | s2++; 36 | } 37 | if (*s1 == *s2) 38 | return (0); 39 | else 40 | return (*s1 < *s2 ? -1 : 1); 41 | } 42 | 43 | /** 44 | * _strstr - checks if needle starts with haystack 45 | * @haystack: string to search 46 | * @needle: the substring to find 47 | * 48 | * Return: address of next char of haystack or NULL 49 | */ 50 | char *_strstr(char *haystack, char *needle) 51 | { 52 | int i; 53 | 54 | for (i = 0; haystack[i] != '\0'; i++) 55 | { 56 | if (haystack[i] == needle[0]) 57 | { 58 | int j; 59 | 60 | for (j = 0; needle[j] != '\0'; j++) 61 | { 62 | if (haystack[i + j] != needle[j]) 63 | { 64 | break; 65 | } 66 | } 67 | 68 | if (needle[j] == '\0') 69 | { 70 | return (&haystack[i]); 71 | } 72 | } 73 | } 74 | return (NULL); 75 | } 76 | 77 | 78 | /** 79 | * _strcat - concatenates two strings 80 | * @dest: the destination buffer 81 | * @src: the source buffer 82 | * 83 | * Return: pointer to destination buffer 84 | */ 85 | char *_strcat(char *dest, char *src) 86 | { 87 | char *ret = dest; 88 | 89 | while (*dest) 90 | dest++; 91 | while (*src) 92 | *dest++ = *src++; 93 | *dest = *src; 94 | return (ret); 95 | } 96 | 97 | /** 98 | * _strchr - a function that locates a character in a string 99 | * 100 | * @s: pointer to our string array input 101 | * @c: character to locate from input array 102 | * 103 | * Return: first occurence of charatcer or null if not found 104 | */ 105 | 106 | char *_strchr(char *s, char c) 107 | { 108 | while (*s != '\0') 109 | { 110 | if (*s == c) 111 | return (s); 112 | s++; 113 | } 114 | /** 115 | * if c is '\0', you should return 116 | * the pointer to the '\0' of the 117 | * string s 118 | */ 119 | if (*s == c) 120 | return (s); 121 | /*return null if not found*/ 122 | return (NULL); 123 | } 124 | -------------------------------------------------------------------------------- /utils_funcs3.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _atoi - Converts a string to an integer. 5 | * @str: The string to convert. 6 | * 7 | * Return: The integer value of the string. 8 | */ 9 | int _atoi(const char *str) 10 | { 11 | int i, sign; 12 | unsigned int num; 13 | 14 | i = 0; 15 | sign = 1; 16 | num = 0; 17 | 18 | while (str[i] != '\0') 19 | { 20 | if (str[i] == '-') 21 | sign *= -1; 22 | else if (str[i] >= '0' && str[i] <= '9') 23 | num = (num * 10) + (str[i] - '0'); 24 | else 25 | break; 26 | i++; 27 | } 28 | return (num * sign); 29 | } 30 | 31 | /** 32 | **_memset - fills memory with a constant byte 33 | *@s: the pointer to the memory area 34 | *@b: the byte to fill *s with 35 | *@n: the amount of bytes to be filled 36 | *Return: (s) a pointer to the memory area s 37 | */ 38 | char *_memset(char *s, char b, unsigned int n) 39 | { 40 | unsigned int i; 41 | 42 | for (i = 0; i < n; i++) 43 | s[i] = b; 44 | return (s); 45 | } 46 | 47 | /** 48 | * _memcpy - function that copies memory area 49 | * 50 | * @dest: buffer where we will copy to 51 | * @src: what we are to copy 52 | * @n: n bytes of @src 53 | * 54 | * Return: Always 0 (Success) 55 | */ 56 | 57 | char *_memcpy(char *dest, char *src, unsigned int n) 58 | { 59 | unsigned int i; 60 | 61 | for (i = 0; i < n; i++) 62 | dest[i] = src[i]; 63 | return (dest); 64 | } 65 | 66 | /** 67 | * _realloc - reallocates a block of memory 68 | * @ptr: pointer to previous malloc'ated block 69 | * @old_size: byte size of previous block 70 | * @new_size: byte size of new block 71 | * 72 | * Return: pointer to da ol'block nameen. 73 | */ 74 | void *_realloc(void *ptr, unsigned int old_size, unsigned int new_size) 75 | { 76 | char *p; 77 | 78 | if (!ptr) 79 | return (malloc(new_size)); 80 | if (!new_size) 81 | return (free(ptr), NULL); 82 | if (new_size == old_size) 83 | return (ptr); 84 | 85 | p = malloc(new_size); 86 | if (!p) 87 | return (NULL); 88 | 89 | old_size = old_size < new_size ? old_size : new_size; 90 | while (old_size--) 91 | p[old_size] = ((char *)ptr)[old_size]; 92 | free(ptr); 93 | return (p); 94 | } 95 | 96 | /** 97 | * _calloc - a function that allocates 98 | * memory for an array using malloc 99 | * 100 | * It is basically the equivalent to 101 | * malloc followed by memset 102 | * 103 | * @nmemb: size of array 104 | * @size: size of each element 105 | * 106 | * Return: pointer with new allocated memory 107 | * or NULL if it fails 108 | */ 109 | 110 | void *_calloc(unsigned int nmemb, unsigned int size) 111 | { 112 | char *p; 113 | 114 | if (nmemb == 0 || size == 0) 115 | return (NULL); 116 | 117 | p = malloc(nmemb * size); 118 | if (p == NULL) 119 | return (NULL); 120 | 121 | _memset(p, 0, nmemb * size); 122 | 123 | return (p); 124 | } 125 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/execute.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * check_for_builtin - checks if the command is a builtin 5 | * @args: the arguments array 6 | * 7 | * Return: 1 if command is a builtin, 0 otherwise 8 | */ 9 | int check_for_builtin(char **args) 10 | { 11 | if (args == NULL || *args == NULL) 12 | return (0); 13 | if (strcmp(*args, "exit") == 0) 14 | return (1); 15 | if (strcmp(*args, "cd") == 0) 16 | return (1); 17 | if (strcmp(*args, "env") == 0) 18 | return (1); 19 | return (0); 20 | } 21 | 22 | /** 23 | * execute - executes a command 24 | * @args: the arguments array 25 | * @path: the PATH variable 26 | * 27 | * Return: 1 on success, 0 on failure 28 | */ 29 | int execute(char **args, char *path) 30 | { 31 | pid_t pid; 32 | char **tokens; 33 | char *command; 34 | int status; 35 | 36 | if (check_for_builtin(args)) 37 | return (1); 38 | 39 | tokens = tokenize(path, ":"); 40 | command = args[0]; 41 | 42 | struct stat sb; 43 | int i = 0; 44 | char *dir; 45 | 46 | while (tokens[i] != NULL) 47 | { 48 | dir = malloc(_strlen(tokens[i]) + _strlen(command) + 2); 49 | _strcpy(dir, tokens[i]); 50 | _strcat(dir, "/"); 51 | _strcat(dir, command); 52 | if (stat(dir, &sb) == 0 && sb.st_mode & S_IXUSR) 53 | { 54 | pid = fork(); 55 | if (pid == -1) 56 | perror("Error"); 57 | if (pid == 0) 58 | { 59 | if (execve(dir, args, environ) == -1) 60 | { 61 | _puterror("Error: Cannot execute command\n"); 62 | free_tokens(tokens); 63 | free(dir); 64 | exit(EXIT_FAILURE); 65 | } 66 | } 67 | else 68 | wait(&status); 69 | free(dir); 70 | free_tokens(tokens); 71 | return (1); 72 | } 73 | i++; 74 | free(dir); 75 | } 76 | _puterror("Error: Command not found\n"); 77 | free_tokens(tokens); 78 | return (0); 79 | } 80 | 81 | /** 82 | * tokenize - splits a string into tokens 83 | * @input: the input string 84 | * @delimiter: the delimiter character 85 | * 86 | * Return: an array of tokens 87 | */ 88 | char **tokenize(char *input, const char *delimiter) 89 | { 90 | char **tokens = NULL; 91 | char *token; 92 | int i = 0; 93 | 94 | token = strtok(input, delimiter); 95 | while (token != NULL) 96 | { 97 | tokens = realloc(tokens, (i + 2) * sizeof(char *)); 98 | if (tokens == NULL) 99 | { 100 | free_tokens(tokens); 101 | return (NULL); 102 | } 103 | tokens[i] = token; 104 | token = strtok(NULL, delimiter); 105 | i++; 106 | } 107 | tokens[i] = NULL; 108 | return (tokens); 109 | } 110 | 111 | 112 | /** 113 | * free_tokens - frees an array of tokens 114 | * @tokens: the array of tokens 115 | */ 116 | void free_tokens(char **tokens) 117 | { 118 | if (tokens == NULL) 119 | return; 120 | int i = 0; 121 | 122 | while (tokens[i] != NULL) 123 | { 124 | free(tokens[i]); 125 | i++; 126 | } 127 | free(tokens); 128 | } 129 | -------------------------------------------------------------------------------- /utils_funcs1.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _strlen - returns the length of a string 5 | * @s: the string whose length to check 6 | * 7 | * Return: integer length of string 8 | */ 9 | int _strlen(const char *s) 10 | { 11 | int i = 0; 12 | 13 | if (!s) 14 | return (0); 15 | 16 | while (*s++) 17 | i++; 18 | return (i); 19 | } 20 | 21 | /** 22 | * _strcmp - Compare two strings. 23 | * @s1: The first string to compare. 24 | * @s2: The second string to compare. 25 | * Return: 0 if @s1 and @s2 are equal, 26 | * a negative value if @s1 is less than @s2, 27 | * or a positive value if @s1 is greater than @s2. 28 | */ 29 | int _strcmp(const char *s1, const char *s2) 30 | { 31 | while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2) 32 | { 33 | s1++; 34 | s2++; 35 | } 36 | 37 | return ((int) (*s1) - (*s2)); 38 | } 39 | 40 | /** 41 | * _strncmp - Compare two strings up to a specified length. 42 | * @s1: First string to compare. 43 | * @s2: Second string to compare. 44 | * @n: Maximum number of characters to compare. 45 | * 46 | * Return: 0 if the strings are equal up to n characters, negative value 47 | * if s1 is less than s2, or positive value if s1 is greater than s2. 48 | */ 49 | int _strncmp(const char *s1, const char *s2, size_t n) 50 | { 51 | unsigned char c1, c2; 52 | 53 | while (n-- > 0) 54 | { 55 | c1 = (unsigned char) *s1++; 56 | c2 = (unsigned char) *s2++; 57 | 58 | if (c1 != c2) 59 | return (c1 - c2); 60 | if (c1 == '\0') 61 | break; 62 | } 63 | 64 | return (0); 65 | } 66 | 67 | /** 68 | * _strstr - checks if needle starts with haystack 69 | * @haystack: string to search 70 | * @needle: the substring to find 71 | * 72 | * Return: address of next char of haystack or NULL 73 | */ 74 | char *_strstr(char *haystack, char *needle) 75 | { 76 | int i; 77 | 78 | for (i = 0; haystack[i] != '\0'; i++) 79 | { 80 | if (haystack[i] == needle[0]) 81 | { 82 | int j; 83 | 84 | for (j = 0; needle[j] != '\0'; j++) 85 | { 86 | if (haystack[i + j] != needle[j]) 87 | { 88 | break; 89 | } 90 | } 91 | 92 | if (needle[j] == '\0') 93 | { 94 | return (&haystack[i]); 95 | } 96 | } 97 | } 98 | return (NULL); 99 | } 100 | 101 | /** 102 | * _strchr - a function that locates a character in a string 103 | * 104 | * @s: pointer to our string array input 105 | * @c: character to locate from input array 106 | * 107 | * Return: first occurence of charatcer or null if not found 108 | */ 109 | 110 | char *_strchr(char *s, char c) 111 | { 112 | while (*s != '\0') 113 | { 114 | if (*s == c) 115 | return (s); 116 | s++; 117 | } 118 | /** 119 | * if c is '\0', you should return 120 | * the pointer to the '\0' of the 121 | * string s 122 | */ 123 | if (*s == c) 124 | return (s); 125 | /*return null if not found*/ 126 | return (NULL); 127 | } 128 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/14-_setenv2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern char **environ; 7 | 8 | /** 9 | * _setenv - set an environment variable 10 | * @name: the name of the environment variable 11 | * @value: the value to set the environment variable to 12 | * @overwrite: whether to overwrite an existing environment variable with the same name 13 | * 14 | * Return: 0 on success, -1 on error 15 | */ 16 | int _setenv(const char *name, const char *value, int overwrite) 17 | { 18 | if (name == NULL || value == NULL) 19 | { 20 | return -1; 21 | } 22 | 23 | // Check if the environment variable already exists 24 | int i = 0; 25 | while (environ[i] != NULL) 26 | { 27 | if (strncmp(name, environ[i], strlen(name)) == 0 && environ[i][strlen(name)] == '=') 28 | { 29 | if (overwrite) 30 | { 31 | // Overwrite the existing variable 32 | size_t new_env_len = strlen(name) + 1 + strlen(value) + 1; 33 | char *new_env = malloc(new_env_len); 34 | if (new_env == NULL) 35 | { 36 | return -1; 37 | } 38 | strcpy(new_env, name); 39 | strcat(new_env, "="); 40 | strcat(new_env, value); 41 | /* free(environ[i]);*/ 42 | environ[i] = new_env; 43 | } 44 | return 0; 45 | } 46 | i++; 47 | } 48 | 49 | // Add a new environment variable 50 | size_t new_env_len = strlen(name) + 1 + strlen(value) + 1; 51 | char *new_env = malloc(new_env_len); 52 | if (new_env == NULL) 53 | { 54 | return -1; 55 | } 56 | strcpy(new_env, name); 57 | strcat(new_env, "="); 58 | strcat(new_env, value); 59 | 60 | // Allocate a new environ array with space for the new variable 61 | int environ_size = i; 62 | char **new_environ = malloc(sizeof(char *) * (environ_size + 2)); 63 | if (new_environ == NULL) 64 | { 65 | free(new_env); 66 | return -1; 67 | } 68 | 69 | // Copy the existing environ array into the new array 70 | for (int j = 0; j < environ_size; j++) 71 | { 72 | new_environ[j] = environ[j]; 73 | } 74 | 75 | // Add the new variable to the new array 76 | new_environ[environ_size] = new_env; 77 | new_environ[environ_size + 1] = NULL; 78 | 79 | // Set the global environ variable to the new array 80 | /* for (i = 0; environ[i]; i++) 81 | free(environ[i]); 82 | free(environ); 83 | */ environ = new_environ; 84 | 85 | return 0; 86 | } 87 | 88 | // C program to illustrate setenv function 89 | int main() 90 | { 91 | char *pth; 92 | int i; 93 | if(_setenv("INCLUDE","usr/nto//include:/home/scholar/include",1)==0) 94 | { 95 | if((pth=getenv("INCLUDE"))!=NULL) 96 | printf("\n\n\tINCLUDE:%s\n\n\t",pth); 97 | free(pth - 8); 98 | } 99 | else 100 | { 101 | printf("\n\n\tError! No such Environment Value Exists."); 102 | } 103 | 104 | /* for (i = 0; environ[i]; i++) 105 | free(environ[i]); 106 | */ free(environ); 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/13-path_list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /** 6 | * A structure to represent a node in the linked list of directories. 7 | */ 8 | typedef struct DirectoryNode 9 | { 10 | char *directory; 11 | struct DirectoryNode *next; 12 | } DirectoryNode; 13 | 14 | /** 15 | * build_path_list - builds a linked list of directories in the PATH environment variable 16 | * 17 | * Return: a pointer to the head of the linked list, or NULL if an error occurred 18 | */ 19 | DirectoryNode *build_path_list() 20 | { 21 | char *path = getenv("PATH"); 22 | if (path == NULL) 23 | { 24 | printf("PATH environment variable not found\n"); 25 | return NULL; 26 | } 27 | 28 | char *path_copy = strdup(path); 29 | if (path_copy == NULL) 30 | { 31 | printf("Error: out of memory\n"); 32 | return NULL; 33 | } 34 | 35 | DirectoryNode *head = NULL; 36 | DirectoryNode *tail = NULL; 37 | 38 | char *dir = strtok(path_copy, ":"); 39 | while (dir != NULL) 40 | { 41 | DirectoryNode *node = (DirectoryNode *)malloc(sizeof(DirectoryNode)); 42 | if (node == NULL) 43 | { 44 | printf("Error: out of memory\n"); 45 | free(path_copy); 46 | return NULL; 47 | } 48 | 49 | node->directory = strdup(dir); 50 | if (node->directory == NULL) 51 | { 52 | printf("Error: out of memory\n"); 53 | free(node); 54 | free(path_copy); 55 | return NULL; 56 | } 57 | 58 | node->next = NULL; 59 | 60 | if (head == NULL) 61 | { 62 | head = node; 63 | tail = node; 64 | } 65 | else 66 | { 67 | tail->next = node; 68 | tail = node; 69 | } 70 | 71 | dir = strtok(NULL, ":"); 72 | } 73 | 74 | free(path_copy); 75 | 76 | return head; 77 | } 78 | 79 | /** 80 | * free_path_list - frees the memory allocated for the linked list of directories 81 | * @head: the head of the linked list 82 | */ 83 | void free_path_list(DirectoryNode *head) 84 | { 85 | DirectoryNode *current = head; 86 | while (current != NULL) 87 | { 88 | DirectoryNode *next = current->next; 89 | free(current->directory); 90 | free(current); 91 | current = next; 92 | } 93 | } 94 | 95 | /** 96 | * print_path_list - prints the linked list of directories to standard output 97 | * @head: the head of the linked list 98 | */ 99 | void print_path_list(DirectoryNode *head) 100 | { 101 | for (DirectoryNode *current = head; current != NULL; current = current->next) 102 | { 103 | printf("%s\n", current->directory); 104 | } 105 | } 106 | 107 | /** 108 | * main - entry point for the program 109 | * @argc: the number of command-line arguments 110 | * @argv: an array of strings containing the command-line arguments 111 | * 112 | * Return: 0 on success, non-zero on error 113 | */ 114 | int main(int argc, char **argv) 115 | { 116 | DirectoryNode *head = build_path_list(); 117 | if (head == NULL) 118 | { 119 | return EXIT_FAILURE; 120 | } 121 | 122 | print_path_list(head); 123 | 124 | free_path_list(head); 125 | 126 | return EXIT_SUCCESS; 127 | } 128 | -------------------------------------------------------------------------------- /shell_practice/0x01-shell/helpers.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _putchar - writes a character to stdout 5 | * @c: character to write 6 | * 7 | * Return: On success 1, on error -1 and errno set appropriately. 8 | */ 9 | int _putchar(char c) 10 | { 11 | return (write(STDOUT_FILENO, &c, 1)); 12 | } 13 | 14 | /** 15 | * _puts - writes a string to stdout 16 | * @str: string to write 17 | */ 18 | void _puts(char *str) 19 | { 20 | int i; 21 | 22 | for (i = 0; str[i] != '\0'; i++) 23 | _putchar(str[i]); 24 | } 25 | 26 | /** 27 | * _puterror - writes an error message to stderr 28 | * @str: error message to write 29 | */ 30 | void _puterror(char *str) 31 | { 32 | int i; 33 | 34 | for (i = 0; str[i] != '\0'; i++) 35 | _putchar(str[i]); 36 | } 37 | 38 | /** 39 | * _strlen - returns the length of a string 40 | * @s: string to get length of 41 | * 42 | * Return: length of the string 43 | */ 44 | int _strlen(char *s) 45 | { 46 | int i; 47 | 48 | for (i = 0; s[i] != '\0'; i++) 49 | ; 50 | 51 | return (i); 52 | } 53 | 54 | /** 55 | * _strcpy - copies a string to a buffer 56 | * @dest: destination buffer 57 | * @src: source string 58 | * 59 | * Return: pointer to dest 60 | */ 61 | char *_strcpy(char *dest, char *src) 62 | { 63 | int i; 64 | 65 | for (i = 0; src[i] != '\0'; i++) 66 | dest[i] = src[i]; 67 | 68 | dest[i] = '\0'; 69 | 70 | return (dest); 71 | } 72 | 73 | /** 74 | * _strcat - concatenates two strings 75 | * @dest: destination string 76 | * @src: source string 77 | * 78 | * Return: pointer to dest 79 | */ 80 | char *_strcat(char *dest, char *src) 81 | { 82 | int i, j; 83 | 84 | for (i = 0; dest[i] != '\0'; i++) 85 | ; 86 | 87 | for (j = 0; src[j] != '\0'; j++) 88 | dest[i + j] = src[j]; 89 | 90 | dest[i + j] = '\0'; 91 | 92 | return (dest); 93 | } 94 | 95 | /** 96 | * _strdup - duplicates a string 97 | * @str: string to duplicate 98 | * 99 | * Return: pointer to the duplicate string 100 | */ 101 | char *_strdup(char *str) 102 | { 103 | char *dup; 104 | int len; 105 | 106 | len = _strlen(str); 107 | 108 | dup = malloc(len + 1); 109 | 110 | if (dup == NULL) 111 | return (NULL); 112 | 113 | _strcpy(dup, str); 114 | 115 | return (dup); 116 | } 117 | 118 | /** 119 | * _strcmp - compares two strings 120 | * @s1: first string 121 | * @s2: second string 122 | * 123 | * Return: 0 if the strings match, non-zero otherwise 124 | */ 125 | int _strcmp(char *s1, char *s2) 126 | { 127 | int i; 128 | 129 | for (i = 0; s1[i] != '\0' && s2[i] != '\0'; i++) 130 | { 131 | if (s1[i] != s2[i]) 132 | return (s1[i] - s2[i]); 133 | } 134 | 135 | if (s1[i] == '\0' && s2[i] == '\0') 136 | return (0); 137 | 138 | return (s1[i] - s2[i]); 139 | } 140 | 141 | /** 142 | * _atoi - converts a string to an integer. 143 | * @s: string to convert. 144 | * 145 | * Return: integer value of the string, 146 | * or -1 if the string is not a valid number. 147 | */ 148 | int _atoi(char *s) 149 | { 150 | int sign = 1, i = 0, num = 0; 151 | 152 | if (s == NULL) 153 | return (-1); 154 | 155 | if (s[i] == '-') 156 | { 157 | sign = -1; 158 | i++; 159 | } 160 | 161 | while (s[i] != '\0') 162 | { 163 | if (s[i] >= '0' && s[i] <= '9') 164 | num = num * 10 + (s[i] - '0'); 165 | else 166 | return (-1); 167 | 168 | i++; 169 | } 170 | 171 | return (num * sign); 172 | } 173 | -------------------------------------------------------------------------------- /shell_practice/0x00-shell/16-_setenv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern char **environ; 8 | 9 | int _sprintf(char *str, const char *format, ...) 10 | { 11 | va_list args; 12 | int i = 0; 13 | 14 | va_start(args, format); 15 | while (*format) 16 | { 17 | // If the format specifier is encountered 18 | if (*format == '%') 19 | { 20 | format++; 21 | switch (*format) 22 | { 23 | case 'd': 24 | { 25 | int arg = va_arg(args, int); 26 | int j = 0, k = arg; 27 | 28 | // Reverse the number 29 | while (k) 30 | { 31 | str[i++] = (k % 10) + '0'; 32 | k /= 10; 33 | j++; 34 | } 35 | 36 | // Reverse the string 37 | for (j = j - 1; j >= 0; j--, i++) 38 | str[i] = str[i - j - 1]; 39 | break; 40 | } 41 | 42 | case 's': 43 | { 44 | char *arg = va_arg(args, char *); 45 | int j = 0; 46 | 47 | // Copy the string 48 | while (arg[j] != '\0') 49 | str[i++] = arg[j++]; 50 | break; 51 | } 52 | } 53 | } 54 | else 55 | str[i++] = *format; 56 | 57 | format++; 58 | } 59 | va_end(args); 60 | 61 | // Add null terminator 62 | str[i] = '\0'; 63 | 64 | return i; 65 | } 66 | 67 | /** 68 | * _setenv - set an environment variable 69 | * @name: the name of the environment variable 70 | * @value: the value to set the environment variable to 71 | * @overwrite: whether to overwrite an existing environment variable with the same name 72 | * 73 | * Return: 0 on success, -1 on error 74 | */ 75 | int _setenv(const char *name, const char *value, int overwrite) 76 | { 77 | int i; 78 | for (i = 0; environ[i] != NULL; i++) { 79 | // Check if the variable is present in the environment 80 | if (strstr(environ[i], name) != NULL) { 81 | // If overwrite is set, then overwrite the existing value 82 | if (overwrite) { 83 | // Build the string in the format "name=value" 84 | char *str = (char *)malloc(strlen(name) + strlen(value) + 2); 85 | _sprintf(str, "%s=%s", name, value); 86 | 87 | // Replace the existing string with the new one 88 | environ[i] = str; 89 | } 90 | 91 | // Variable is changed or added 92 | return 0; 93 | } 94 | } 95 | 96 | // Variable not found, so add it 97 | environ[i] = (char *)malloc(strlen(name) + strlen(value) + 2); 98 | _sprintf(environ[i], "%s=%s", name, value); 99 | return 0; 100 | } 101 | 102 | int main() 103 | { 104 | char *pth; 105 | int i; 106 | if(_setenv("INCLUDE","usr/nto//include:/home/scholar/include",1)==0) 107 | { 108 | if((pth=getenv("INCLUDE"))!=NULL) 109 | printf("\n\n\tINCLUDE:%s\n\n\t",pth); 110 | free(pth - 8); 111 | } 112 | else 113 | { 114 | printf("\n\n\tError! No such Environment Value Exists."); 115 | } 116 | 117 | /* for (i = 0; environ[i]; i++) 118 | free(environ[i]); 119 | free(environ); 120 | */ return 0; 121 | } 122 | -------------------------------------------------------------------------------- /test_files/test_env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################ 4 | # Description for the intranet check (one line, support Markdown syntax) 5 | # Remove all environment variables, except one, and execute `env` 6 | 7 | ################################################################################ 8 | # The variable 'compare_with_sh' IS OPTIONNAL 9 | # 10 | # Uncomment the following line if you don't want the output of the shell 11 | # to be compared against the output of /bin/sh 12 | # 13 | # It can be useful when you want to check a builtin command that sh doesn't 14 | # implement 15 | # compare_with_sh=0 16 | 17 | ################################################################################ 18 | # The variable 'shell_input' HAS TO BE DEFINED 19 | # 20 | # The content of this variable will be piped to the student's shell and to sh 21 | # as follows: "echo $shell_input | ./hsh" 22 | # 23 | # It can be empty and multiline 24 | shell_input="env" 25 | 26 | ################################################################################ 27 | # The variable 'shell_params' IS OPTIONNAL 28 | # 29 | # The content of this variable will be passed to as the paramaters array to the 30 | # shell as follows: "./hsh $shell_params" 31 | # 32 | # It can be empty 33 | # shell_params="" 34 | 35 | ################################################################################ 36 | # The function 'check_setup' will be called BEFORE the execution of the shell 37 | # It allows you to set custom VARIABLES, prepare files, etc 38 | # If you want to set variables for the shell to use, be sure to export them, 39 | # since the shell will be launched in a subprocess 40 | # 41 | # Return value: Discarded 42 | function check_setup() 43 | { 44 | current_env=$(/usr/bin/env) 45 | for i in `/usr/bin/env | /usr/bin/cut -d'=' -f1` 46 | do 47 | unset $i 48 | done 49 | 50 | export HBTN="Holberton" 51 | 52 | return 0 53 | } 54 | 55 | ################################################################################ 56 | # The function 'sh_setup' will be called AFTER the execution of the students 57 | # shell, and BEFORE the execution of the real shell (sh) 58 | # It allows you to set custom VARIABLES, prepare files, etc 59 | # If you want to set variables for the shell to use, be sure to export them, 60 | # since the shell will be launched in a subprocess 61 | # 62 | # Return value: Discarded 63 | function sh_setup() 64 | { 65 | return 0 66 | } 67 | 68 | ################################################################################ 69 | # The function `check_callback` will be called AFTER the execution of the shell 70 | # It allows you to clear VARIABLES, cleanup files, ... 71 | # 72 | # It is also possible to perform additionnal checks. 73 | # Here is a list of available variables: 74 | # STATUS -> Path to the file containing the exit status of the shell 75 | # OUTPUTFILE -> Path to the file containing the stdout of the shell 76 | # ERROR_OUTPUTFILE -> Path to the file containing the stderr of the shell 77 | # EXPECTED_STATUS -> Path to the file containing the exit status of sh 78 | # EXPECTED_OUTPUTFILE -> Path to the file containing the stdout of sh 79 | # EXPECTED_ERROR_OUTPUTFILE -> Path to the file continaing the stderr of sh 80 | # 81 | # Parameters: 82 | # $1 -> Status of the comparison with sh 83 | # 0 -> The output is the same as sh 84 | # 1 -> The output differs from sh 85 | # 86 | # Return value: 87 | # 0 -> Check succeed 88 | # 1 -> Check fails 89 | function check_callback() 90 | { 91 | let status=0 92 | 93 | # Remove environment variables and set by valgrind from student output 94 | content=`$CAT "$OUTPUTFILE"` 95 | content=`$ECHO "$content" | $GREP -v -e "^GLIBCPP_FORCE_NEW="` 96 | content=`$ECHO "$content" | $GREP -v -e "^GLIBCXX_FORCE_NEW="` 97 | content=`$ECHO "$content" | $GREP -v -e "^LD_PRELOAD="` 98 | content=`$ECHO "$content" | $GREP -v -e "^LD_LIBRARY_PATH="` 99 | content=`$ECHO "$content" | $GREP -v -e "^_="` 100 | content=`$ECHO "$content" | $GREP -v -e "^PWD="` 101 | $ECHO "$content" > $OUTPUTFILE 102 | 103 | # Remove "_" environment variable from expected output 104 | content=`$CAT "$EXPECTED_OUTPUTFILE"` 105 | content=`$ECHO "$content" | $GREP -v -e "^_="` 106 | content=`$ECHO "$content" | $GREP -v -e "^PWD="` 107 | $ECHO "$content" > $EXPECTED_OUTPUTFILE 108 | 109 | $ECHO -n "" > $EXPECTED_ERROR_OUTPUTFILE 110 | $ECHO -n "0" > $EXPECTED_STATUS 111 | 112 | check_diff 113 | 114 | return $status 115 | } 116 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | shaqmwa@outlook.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # alx-low_level_programming 2 | 3 | # Shell Project 4 | This project is a simple UNIX command-line interpreter, also known as a shell. It is capable of reading commands from standard input, parsing them, and executing them. 5 | 6 | ## 0x16. C - Simple Shell 7 | 8 | ### Pre-requisites 9 | 10 | #### Authorized functions and macros: 11 | - access (man 2 access) 12 | - chdir (man 2 chdir) 13 | - close (man 2 close) 14 | - closedir (man 3 closedir) 15 | - execve (man 2 execve) 16 | - exit (man 3 exit) 17 | - _exit (man 2 _exit) 18 | - fflush (man 3 fflush) 19 | - fork (man 2 fork) 20 | - free (man 3 free) 21 | - getcwd (man 3 getcwd) 22 | - getline (man 3 getline) 23 | - isatty (man 3 isatty) 24 | - kill (man 2 kill) 25 | - malloc (man 3 malloc) 26 | - open (man 2 open) 27 | - opendir (man 3 opendir) 28 | - perror (man 3 perror) 29 | - read (man 2 read) 30 | - readdir (man 3 readdir) 31 | - signal (man 2 signal) 32 | - stat (__xstat) (man 2 stat) 33 | - lstat (__lxstat) (man 2 lstat) 34 | - fstat (__fxstat) (man 2 fstat) 35 | - strtok (man 3 strtok) 36 | - wait (man 2 wait) 37 | - waitpid (man 2 waitpid) 38 | - wait3 (man 2 wait3) 39 | - wait4 (man 2 wait4) 40 | - write (man 2 write) 41 | 42 | 43 | ## Project Structure 44 | 45 | The project is organized as follows: 46 | 47 | ``` 48 | . 49 | ├── AUTHORS 50 | ├── README.md 51 | ├── LICENSE 52 | ├── CODE_OF_CONDUCT.md 53 | ├── simple_shell.1 (man page) 54 | ├── shell.h 55 | ├── main.c 56 | ├── get_input.c 57 | ├── get_line.c* 58 | ├── prompt.c 59 | ├── tokenizer.c 60 | ├── execute.c 61 | ├── free.c 62 | ├── signal_handler.c 63 | ├── built-ins Funcs: 64 | │ ├── get_env.c 65 | │ ├── bultins_shell_cd.c 66 | │ ├── bultins_shell_exit.c 67 | │ ├── bultins_shell_help.c 68 | │ ├── bultins_set_env.c 69 | │ └──── bultins_unset_env 70 | ├── Path Funcs: 71 | │ ├── get_path.c 72 | │ ├── find_in_path.c 73 | │ ├── set_path.c 74 | │ ├── append_to_path.c 75 | │ └── prepend_to_path.c 76 | ├── error.c 77 | └── utils: 78 | ├── utils_func1.c 79 | ├── utils_func2.c 80 | └── utils_func2.c 81 | 82 | ``` 83 | 84 | 85 | `AUTHORS` file lists the contributors to the project. 86 | 87 | `README.md` file you are currently reading is a brief overview of the project. 88 | 89 | `man_1_simple_shell` file is the man page for the shell. 90 | 91 | `shell.h`: a header file that includes all the necessary libraries, function prototypes, and global variables. 92 | 93 | `main.c`: the main file that contains the loop for getting the user input, parsing the input, and executing the command. 94 | 95 | `prompt.c`: a file that handles the prompt display for the shell. 96 | 97 | `execute.c`: a file that contains the functions for executing the non-built-in commands. 98 | 99 | `parser.c` : This file contains the implementation of functions for parsing user input into arguments. 100 | 101 | `free.c`: This file contains the implementation of functions for deallocating memory. 102 | 103 | `signal_handler.c`: This file contains the implementation of signal handler functions for handling SIGINT, SIGTSTP and SIGQUIT signals. 104 | 105 | `builtins funcs`: These are the source code files that contains functions related to the implementations of the built-in commands (cd, exit, env, setenv, unsetenv and help). 106 | 107 | `path funcs`: These are the source code files that contains functions related to working with the system's PATH environment variable, such as finding a command in the PATH, getting the current PATH, and setting or modifying the PATH. 108 | 109 | `utils.c`: a file that contains utility functions for the shell, such as string manipulation functions and functions for printing error messages. 110 | 111 | `error.c`: This file contains the implementation of functions for handling errors. 112 | 113 | `Makefile`: a file that specifies the compilation rules for the shell. 114 | 115 | `test_files`: These are test files for each of the implementation files in source_files. 116 | 117 | This tree separates the implementation files from the test files, making it easier to navigate the project and run the tests. 118 | 119 | ## Function Prototypes. 120 | 121 | The header file declares several function prototypes for the shell program, including: 122 | 123 | `prompt()`: prints the shell prompt 124 | 125 | `execute()`: executes a command with arguments 126 | 127 | `get_line()`: Read input from the standard input. Custom getline(). 128 | 129 | `get_input()`: Retrieves user input from stdin. Uses getline(). 130 | 131 | `tokenize()`: parsing user input into arguments. 132 | 133 | `handle_sigint()`: signal handler for SIGINT 134 | 135 | `handle_sigstp()`: signal handler for SIGSTP 136 | 137 | `handle_sigquit()`: signal handler for SIGQUIT 138 | 139 | `check_for_builtin()`: checks if a command is a shell builtin 140 | 141 | `shell_env()`: prints environment variables 142 | 143 | `shell_setenv()`: sets an environment variable 144 | 145 | `shell_unsetenv()`: unsets an environment variable 146 | 147 | `shell_help()`: prints help information for the shell 148 | 149 | `shell_cd()`: changes the current working directory 150 | 151 | `shell_exit()`: exits the shell program with a status code 152 | 153 | `_getenv()`: retrieves the value of an environment variable 154 | 155 | `find_in_path()`: searches for a command in the directories specified by the PATH environment variable 156 | 157 | `get_path()`: retrieves the PATH environment variable 158 | 159 | `set_path()`: sets the PATH environment variable 160 | 161 | `append_to_path()`: appends a directory to the PATH environment variable 162 | 163 | `prepend_to_path()`: prepends a directory to the PATH environment variable 164 | 165 | `free_error()`: frees memory allocated following system error 166 | 167 | `free_tokens()`: frees memory allocated for tokens 168 | 169 | `_puterror()`: prints an error message 170 | 171 | `_puts()`: prints a string 172 | 173 | `_atoi()`: converts a string to an integer 174 | 175 | `_putchar()`: prints a character 176 | 177 | `_strlen()`: gets the length of a string 178 | 179 | `_strcmp()`: compares two strings 180 | 181 | `_strcpy()`: copies a string 182 | 183 | `_strcat()`: concatenates two strings 184 | 185 | `_strdup()`: duplicates a string 186 | 187 | `_strchr()`: searches a string for a character 188 | 189 | `_strstr()`: searches for the first occurrence of a substring 190 | 191 | `_strspn()`: gets the length of a prefix substring 192 | 193 | ## Usage 194 | 195 | To use the simple shell, compile the files using `gcc -Wall -Werror -Wextra -pedantic *.c -o hsh`. Then, run the shell using `./hsh`. 196 | 197 | ` 198 | gcc -Wall -Werror -Wextra -pedantic *.c -o hsh 199 | ` 200 | 201 | This wil compile all the '.c' files and change the output's name to 'hsh'. 202 | 203 | ### Template to test output: 204 | ============= 205 | ``` 206 | $ ./hsh 207 | 208 | ($) ls 209 | 210 | hsh main.c shell.c shell.h 211 | 212 | $ exit 213 | $ 214 | ``` 215 | 216 | also in non-interactive mode: 217 | ``` 218 | $ echo "/bin/ls" | ./hsh 219 | hsh main.c shell.c test_ls_2 220 | $ 221 | $ cat test_ls_2 222 | /bin/ls 223 | /bin/ls 224 | $ 225 | $ cat test_ls_2 | ./hsh 226 | hsh main.c shell.c test_ls_2 227 | hsh main.c shell.c test_ls_2 228 | $ 229 | ``` 230 | 231 | ## Man Page. 232 | 233 | To generate a man page for the `simple_shell`, you can use the `ronn` utility. `ronn` allows you to write man pages in Markdown format and then convert them to man page format. 234 | 235 | Once you have created the `simple_shell.1.md` file, run the following command to generate the man page: 236 | 237 | `ronn simple_shell.1.md` 238 | 239 | This will create a new file called `simple_shell.1`. You can view the man page by running the following command: 240 | 241 | `man ./simple_shell.1` 242 | 243 | ## AUTHORS 244 | 245 | This program was written by `FourtyThree43` and `Kemboiray`. 246 | 247 | ## License 248 | 249 | This project is licensed under the MIT License - see the LICENSE file for details. 250 | -------------------------------------------------------------------------------- /test_files/checker.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################ 4 | # SET SOME CONFIG VARIABLES 5 | ################################################################################ 6 | R=$RANDOM 7 | 8 | TMP_DIR="/tmp" 9 | COMMANDFILE="$TMP_DIR/hbtn_checker_command_$R" 10 | COMMANDFILE_REAL_SHELL="$TMP_DIR/hbtn_checker_command_real_shell_$R" 11 | STATUS="$TMP_DIR/hbtn_checker_status_$R" 12 | OUTPUTFILE="$TMP_DIR/hbtn_checker_output_$R" 13 | ERROR_OUTPUTFILE="$TMP_DIR/hbtn_checker_error_output_$R" 14 | VALGRIND_OUTPUTFILE="$TMP_DIR/hbtn_checker_valgrind_$R" 15 | LTRACE_OUTPUTFILE="$TMP_DIR/hbtn_checker_ltrace_output_$R" 16 | EXPECTED_STATUS="$TMP_DIR/hbtn_checker_expected_status_$R" 17 | EXPECTED_OUTPUTFILE="$TMP_DIR/hbtn_checker_expected_output_$R" 18 | EXPECTED_ERROR_OUTPUTFILE="$TMP_DIR/hbtn_checker_expected_error_output_$R" 19 | TMP_FILE="$TMP_DIR/hbtn_checker_tmp_$R" 20 | ENV_TMP_FILE="$TMP_DIR/hbtn_env_$R" 21 | LTRACE_ALLOWED_FUNCTIONS_FILE="./allowed_functions" 22 | 23 | ################################################################################ 24 | # MOST USED COMMANDS, IN CASE THE ENVIRONMENT IS MISSING 25 | ################################################################################ 26 | WHICH="/usr/bin/which" 27 | SLEEP=`$WHICH sleep` 28 | SLEEPSECONDS=2 # Valgrind needs at least 2 seconds to execute properly 29 | LTRACE=`$WHICH ltrace` 30 | ECHO=`$WHICH echo` 31 | CAT=`$WHICH cat` 32 | GREP=`$WHICH grep` 33 | WC=`$WHICH wc` 34 | RM=`$WHICH rm` 35 | TOUCH=`$WHICH touch` 36 | CHMOD=`$WHICH chmod` 37 | PIDOF=`$WHICH pidof` 38 | KILLALL=`$WHICH killall` 39 | KILL=`$WHICH kill` 40 | VALGRIND=`$WHICH valgrind` 41 | SED=`$WHICH sed` 42 | DIFF=`$WHICH diff` 43 | HEAD=`$WHICH head` 44 | TAIL=`$WHICH tail` 45 | CUT=`$WHICH cut` 46 | PS=`$WHICH ps` 47 | HEAD=`$WHICH head` 48 | CP=`$WHICH cp` 49 | ENV=`$WHICH env` 50 | 51 | ################################################################################ 52 | # COMMAND-LINE OPTIONS AND PARAMETERS 53 | ################################################################################ 54 | usage=0 55 | 56 | valgrind_error=0 57 | valgrind_leak=0 58 | ltrace=0 59 | 60 | force_diff=0 61 | 62 | function usage() 63 | { 64 | exitcode=$1 65 | 66 | $ECHO "Usage: $0 shell test_file 67 | 68 | Options: 69 | --valgrind_error Checks for valgrind errors 70 | --valgrind_leak Cehcks for valgrind leaks 71 | --valgrind Checks for both valgrind errors and leaks 72 | --ltrace Checks for forbidden system/library calls 73 | 74 | --diff Force to print the output diff 75 | 76 | --help Prints the help and exit" 77 | 78 | exit $exitcode 79 | } 80 | 81 | ################################################################################ 82 | # PARSE COMMAND-LINE PARAMETERS 83 | ################################################################################ 84 | for arg in "$@" 85 | do 86 | if [ "$arg" == "--valgrind_error" ] 87 | then 88 | let valgrind_error=1 89 | shift $ARGV 90 | elif [ "$arg" == "--valgrind_leak" ] 91 | then 92 | let valgrind_leak=1 93 | shift $ARGV 94 | elif [ "$arg" == "--valgrind" ] 95 | then 96 | let valgrind_error=1 97 | let valgrind_leak=1 98 | shift $ARGV 99 | elif [ "$arg" == "--ltrace" ] 100 | then 101 | let ltrace=1 102 | shift $ARGV 103 | elif [ "$arg" == "--diff" ] 104 | then 105 | let force_diff=1 106 | shift $ARGV 107 | elif [ "$arg" == "--help" ] 108 | then 109 | let usage=1 110 | shift $ARGV 111 | fi 112 | done 113 | 114 | [[ "$usage" -eq "1" ]] && usage 0 115 | [[ "$#" -lt "2" ]] && usage 1 116 | 117 | HSHELL=$1 118 | TEST_FILE=$2 119 | REAL_SHELL=`$WHICH sh` 120 | 121 | ################################################################################ 122 | # UTILITIES FUNCTIONS 123 | ################################################################################ 124 | function stop_process() 125 | { 126 | prog=$1 127 | base_shell=${prog##*/} 128 | 129 | # for pid in `ps aux | grep "$base_shell" | cut -d' ' -f3` 130 | # do 131 | # kill -9 $pid > /dev/null 2>&1 132 | # done 133 | 134 | running_shells=`$PIDOF "$base_shell" | $WC -l` 135 | if [ "$running_shells" -ne "0" ] 136 | then 137 | $KILLALL -9 "$base_shell" > /dev/null 2>&1 138 | fi 139 | } 140 | 141 | function cleanup() 142 | { 143 | stop_process $HSHELL 144 | $RM -f $COMMANDFILE 145 | $RM -f $COMMANDFILE_REAL_SHELL 146 | $RM -f $STATUS 147 | $RM -f $OUTPUTFILE 148 | $RM -f $ERROR_OUTPUTFILE 149 | $RM -f $CHECK_OUTPUTFILE 150 | $RM -f $VALGRIND_OUTPUTFILE 151 | $RM -f $LTRACE_OUTPUTFILE 152 | $RM -f $EXPECTED_STATUS 153 | $RM -f $EXPECTED_OUTPUTFILE 154 | $RM -f $EXPECTED_ERROR_OUTPUTFILE 155 | $RM -f $TMP_FILE 156 | $RM -f $ENV_TMP_FILE 157 | } 158 | 159 | function print_diff() 160 | { 161 | input=$1 162 | params=$2 163 | 164 | $ECHO -n "(command)[" 165 | if [ ! -z "$input" ] 166 | then 167 | $ECHO -e -n "echo \"$input\" | " 168 | fi 169 | $ECHO -n "$HSHELL" 170 | if [ ! -z "$params" ] 171 | then 172 | $ECHO -n " $params" 173 | fi 174 | $ECHO "]" 175 | $ECHO "" 176 | 177 | $ECHO "[GOT]:" 178 | $ECHO -n "(stdout)[" 179 | $CAT $OUTPUTFILE 180 | $ECHO "](Length: `$CAT $OUTPUTFILE | $WC -c`)" 181 | $ECHO -n "(stderr)[" 182 | $CAT $ERROR_OUTPUTFILE 183 | $ECHO "](Length: `$CAT $ERROR_OUTPUTFILE | $WC -c`)" 184 | $ECHO -n "(status)[" 185 | $CAT $STATUS 186 | $ECHO -e "]\n" 187 | 188 | $ECHO "[EXPECTED]:" 189 | $ECHO -n "(stdout)[" 190 | $CAT $EXPECTED_OUTPUTFILE 191 | $ECHO "](Length: `$CAT $EXPECTED_OUTPUTFILE | $WC -c`)" 192 | $ECHO -n "(stderr)[" 193 | $CAT $EXPECTED_ERROR_OUTPUTFILE 194 | $ECHO "](Length: `$CAT $EXPECTED_ERROR_OUTPUTFILE | $WC -c`)" 195 | $ECHO -n "(status)[" 196 | $CAT $EXPECTED_STATUS 197 | $ECHO -e "]\n" 198 | 199 | $ECHO "Environment:" 200 | $CAT $ENV_TMP_FILE | $GREP -v "LS_COLORS" 201 | } 202 | 203 | ################################################################################ 204 | # START 205 | ################################################################################ 206 | stop_process $HSHELL 207 | status=0 208 | params="" 209 | 210 | ################################################################################ 211 | # READ AND EXECUTE CHECK SCRIPT 212 | ################################################################################ 213 | source $TEST_FILE 214 | 215 | ################################################################################ 216 | # REATRIEVE SHELL INPUT (STDIN) AND PARAMS 217 | ################################################################################ 218 | if [ -z ${shell_input+x} ] 219 | then 220 | echo "The variable \$shell_input is not defined in $TEST_FILE!" 221 | exit 1 222 | fi 223 | if [ ! -z ${shell_params+x} ] 224 | then 225 | params=$shell_params 226 | fi 227 | 228 | ################################################################################ 229 | # FUNCTION "check_setup" CAN BE DEFINED IN THE CHECK SCRIPT 230 | ################################################################################ 231 | if [ -n "$(type -t check_setup)" ] && [ "$(type -t check_setup)" = function ] 232 | then 233 | check_setup 234 | fi 235 | 236 | shell_pid=0 237 | shell_ppid=0 238 | differs=0 239 | 240 | ################################################################################ 241 | # PREPARING COMMAND SCRIPT FILE 242 | ################################################################################ 243 | $ECHO -e -n "$ECHO " > $COMMANDFILE 244 | $ECHO -e -n "\"$shell_input\"" >> $COMMANDFILE 245 | $ECHO -e -n " | " >> $COMMANDFILE 246 | if [ $valgrind_error -ne 0 ] || [ $valgrind_leak -ne 0 ] 247 | then 248 | $ECHO -e -n "$VALGRIND --log-file=\"$VALGRIND_OUTPUTFILE\" " >> $COMMANDFILE 249 | fi 250 | $ECHO -e "\"$HSHELL\" $params > \"$OUTPUTFILE\" 2> \"$ERROR_OUTPUTFILE\"" >> $COMMANDFILE 251 | $ECHO -e "$ECHO -n \$? > \"$STATUS\"" >> $COMMANDFILE 252 | $CHMOD +x $COMMANDFILE 253 | 254 | ################################################################################ 255 | # TEST COMMAND AGAINST STUDENT SHELL 256 | ################################################################################ 257 | . $COMMANDFILE & 258 | $SLEEP $SLEEPSECONDS 259 | stop_process $COMMANDFILE 260 | # stop_process $HSHELL 261 | 262 | ################################################################################ 263 | # PARSE VALGRIND OUTPUT TO RETRIEVE SHELL PID 264 | ################################################################################ 265 | if [ $valgrind_error -ne 0 ] || [ $valgrind_leak -ne 0 ] 266 | then 267 | # stop valgrind 268 | valgrind_pid=`$PIDOF valgrind.bin` 269 | if [ -n "$valgrind_pid" ] 270 | then 271 | $KILL -9 "$valgrind_pid" > /dev/null 2>&1 272 | fi 273 | 274 | content=`$CAT $VALGRIND_OUTPUTFILE` 275 | regex="==([0-9]+)== Parent PID: ([0-9]+)" 276 | if [[ $content =~ $regex ]] 277 | then 278 | let shell_pid=${BASH_REMATCH[1]} 279 | let shell_ppid=${BASH_REMATCH[2]} 280 | 281 | # DISCARD PARENT PROCESS OUTPUT 282 | $ECHO "$content" | $GREP -v -e "^==$shell_ppid" > $VALGRIND_OUTPUTFILE 283 | fi 284 | fi 285 | 286 | ################################################################################ 287 | # RUN LTRACE 288 | ################################################################################ 289 | if [ $ltrace -ne 0 ] 290 | then 291 | ($ECHO "$shell_input" | $LTRACE -bc -o "$LTRACE_OUTPUTFILE" "$HSHELL" $params > /dev/null 2>&1 &) 292 | $SLEEP $SLEEPSECONDS 293 | stop_process $LTRACE 294 | fi 295 | 296 | function check_diff() 297 | { 298 | let differs=0 299 | 300 | ######################################################################## 301 | # CHECK DIFF 302 | ######################################################################## 303 | diff_out=`$DIFF $OUTPUTFILE $EXPECTED_OUTPUTFILE` 304 | diff_err=`$DIFF $ERROR_OUTPUTFILE $EXPECTED_ERROR_OUTPUTFILE` 305 | diff_status=`$DIFF $STATUS $EXPECTED_STATUS` 306 | if [ ! -z "$diff_out" ] || [ ! -z "$diff_err" ] || [ ! -z "$diff_status" ] 307 | then 308 | let differs=1 309 | let status=1 310 | fi 311 | } 312 | 313 | ################################################################################ 314 | # FUNCTION "sh_setup" CAN BE DEFINED IN THE CHECK SCRIPT 315 | ################################################################################ 316 | if [ -n "$(type -t sh_setup)" ] && [ "$(type -t sh_setup)" = function ] 317 | then 318 | sh_setup 319 | fi 320 | 321 | ################################################################################ 322 | # RUN SH IN ORDER TO COMPARE OUTPUTS 323 | ################################################################################ 324 | if [ -z ${compare_with_sh+x} ] || [ $compare_with_sh -ne 0 ] 325 | then 326 | ######################################################################## 327 | # PREPARING COMMAND SCRIPT FILE 328 | ######################################################################## 329 | $ECHO -e -n "$ECHO " > $COMMANDFILE_REAL_SHELL 330 | $ECHO -e -n "\"$shell_input\"" >> $COMMANDFILE_REAL_SHELL 331 | cmd=" | \"$REAL_SHELL\" $params > \"$EXPECTED_OUTPUTFILE\" 2> \"$EXPECTED_ERROR_OUTPUTFILE\" ; $ECHO -n \$? > \"$EXPECTED_STATUS\"" 332 | $ECHO -e $cmd >> $COMMANDFILE_REAL_SHELL 333 | $CHMOD +x $COMMANDFILE_REAL_SHELL 334 | 335 | . $COMMANDFILE_REAL_SHELL & 336 | 337 | $SLEEP $SLEEPSECONDS 338 | stop_process $COMMANDFILE_REAL_SHELL 339 | 340 | # REPLACE REAL SHELL'S NAME WITH STUDENT'S SHELL NAME ON ERROR OUTPUT 341 | # EXAMPLE: '/bin/sh: 1: qwerty: not found' 342 | # BECOMES: './hsh: 1: qwerty: not found' 343 | $SED -i "s@${REAL_SHELL}@${HSHELL}@g" $EXPECTED_OUTPUTFILE 344 | $SED -i "s@${REAL_SHELL}@${HSHELL}@g" $EXPECTED_ERROR_OUTPUTFILE 345 | 346 | check_diff 347 | fi 348 | 349 | ################################################################################ 350 | # Save environment used during correction 351 | ################################################################################ 352 | $ENV > $ENV_TMP_FILE 353 | 354 | ################################################################################ 355 | # FUNCTION "check_callback" CAN BE DEFINED IN THE CHECK SCRIPT 356 | ################################################################################ 357 | if [ -n "$(type -t check_callback)" ] && [ "$(type -t check_callback)" = function ] 358 | then 359 | check_callback $status 360 | let status=$? 361 | fi 362 | 363 | ################################################################################ 364 | # PRINT OUTPUTS COMPARISON 365 | ################################################################################ 366 | if [ $differs -ne 0 ] || [ $force_diff -ne 0 ] 367 | then 368 | print_diff "$shell_input" "$params" 369 | fi 370 | 371 | errors=0 372 | leaks=0 373 | ################################################################################ 374 | # CHECK VALGRIND ERRORS AND MEMORY LEAKS 375 | ################################################################################ 376 | if [ $valgrind_error -ne 0 ] || [ $valgrind_leak -ne 0 ] 377 | then 378 | ######################################################################## 379 | # CHECK FOR VALGRIND ERRORS 380 | ######################################################################## 381 | content=`$CAT $VALGRIND_OUTPUTFILE` 382 | regex="ERROR SUMMARY: ([1-9][0-9]*) errors" 383 | if [[ $content =~ $regex ]] 384 | then 385 | let errors=1 386 | fi 387 | 388 | ######################################################################## 389 | # CHECK FOR VALGRIND LEAKS 390 | ######################################################################## 391 | content=`$CAT $VALGRIND_OUTPUTFILE` 392 | regex="(LEAK SUMMARY:)" 393 | if [[ $content =~ $regex ]] 394 | then 395 | let leaks=1 396 | fi 397 | 398 | ######################################################################## 399 | # PRINT VALGRIND LOG IF ERROR OR LEAK DETECTED 400 | ######################################################################## 401 | if [ $errors -ne 0 ] || [ $leaks -ne 0 ] 402 | then 403 | $ECHO "[VALGRIND]:" 404 | $CAT "$VALGRIND_OUTPUTFILE" 405 | $ECHO "" 406 | 407 | let status=1 408 | fi 409 | fi 410 | 411 | ################################################################################ 412 | # CHECK LTRACE 413 | ################################################################################ 414 | if [ $ltrace -ne 0 ] 415 | then 416 | ######################################################################## 417 | # PARSE LTRACE OUTPUT TO KEEP ONLY A LIST OF CALLED FUNCTIONS 418 | ######################################################################## 419 | functions_called=`$CAT $LTRACE_OUTPUTFILE | $HEAD -n -2 | $TAIL -n +3 | $SED -e 's/ */ /g' | $SED -e 's/^ //g' | $CUT -d' ' -f5 | $GREP -vw 'function' | $GREP -vwe '--------------------' | $GREP -vw 'calls'` 420 | 421 | for f in $functions_called 422 | do 423 | ################################################################ 424 | # CHECK THAT THE FUNCTION IS PART OF THE ALLOWED FUNCTIONS 425 | ################################################################ 426 | if [ `$GREP -w "$f" "$LTRACE_ALLOWED_FUNCTIONS_FILE" | $WC -l` -eq 0 ] 427 | then 428 | $ECHO "Function '$f' is not allowed" 429 | let status=1 430 | fi 431 | done 432 | fi 433 | 434 | ################################################################################ 435 | # CLEANUP AND QUIT 436 | ################################################################################ 437 | cleanup 438 | 439 | [[ $status -eq 0 ]] && $ECHO -n "OK" 440 | exit $status --------------------------------------------------------------------------------