├── .simple_shell_history ├── AUTHORS ├── README.md ├── _atoi.c ├── builtin.c ├── builtin1.c ├── environ.c ├── errors.c ├── errors1.c ├── exits.c ├── getLine.c ├── getenv.c ├── getinfo.c ├── history.c ├── lists.c ├── lists1.c ├── main.c ├── man_1_simple_shell ├── memory.c ├── parser.c ├── realloc.c ├── shell.h ├── shell_loop.c ├── string.c ├── string1.c ├── tokenizer.c └── vars.c /.simple_shell_history: -------------------------------------------------------------------------------- 1 | ls 2 | betty utility.c 3 | gcc utility.c 4 | clear 5 | ls 6 | gcc utility.c 7 | exit 8 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This file lists all individuals having contributed content to the repository. 2 | # For how it is generated, see `hack/generate-authors.sh`. 3 | 4 | Lordwill1 5 | ejilistic 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 0x16. C - Simple Shell 2 | **By Spencer Cheng, featuring Julien Barbier** 3 | Project to be done in teams of 2 people (your team: Godswill Kalu, Vatalis Ibeh) 4 | 5 | # Learning Objectives 6 | At the end of this project, you are expected to be able to explain to anyone, without the help of Google: 7 | 8 | # General 9 | Who designed and implemented the original Unix operating system 10 | Who wrote the first version of the UNIX shell 11 | Who invented the B programming language (the direct predecessor to the C programming language) 12 | Who is Ken Thompson 13 | How does a shell work 14 | What is a pid and a ppid 15 | How to manipulate the environment of the current process 16 | What is the difference between a function and a system call 17 | How to create processes 18 | What are the three prototypes of main 19 | How does the shell use the PATH to find the programs 20 | How to execute another program with the execve system call 21 | How to suspend the execution of a process until one of its children terminates 22 | What is EOF / “end-of-file”? 23 | # Requirements 24 | # General 25 | Allowed editors: vi, vim, emacs 26 | All your files will be compiled on Ubuntu 20.04 LTS using gcc, using the options -Wall -Werror -Wextra -pedantic -std=gnu89 27 | All your files should end with a new line 28 | A README.md file, at the root of the folder of the project is mandatory 29 | Your code should use the Betty style. It will be checked using betty-style.pl and betty-doc.pl 30 | Your shell should not have any memory leaks 31 | No more than 5 functions per file 32 | All your header files should be include guarded 33 | Use system calls only when you need to (why?) 34 | # GitHub 35 | *There should be one project repository per group. If you and your partner have a repository with the same name in both your accounts, you risk a 0% score. Add your partner as a collaborator. * 36 | 37 | More Info 38 | Output 39 | Unless specified otherwise, your program must have the exact same output as sh (/bin/sh) as well as the exact same error output. 40 | The only difference is when you print an error, the name of the program must be equivalent to your argv[0] (See below) 41 | Example of error with sh: 42 | 43 | $ echo "qwerty" | /bin/sh 44 | /bin/sh: 1: qwerty: not found 45 | $ echo "qwerty" | /bin/../bin/sh 46 | /bin/../bin/sh: 1: qwerty: not found 47 | $ 48 | Same error with your program hsh: 49 | 50 | $ echo "qwerty" | ./hsh 51 | ./hsh: 1: qwerty: not found 52 | $ echo "qwerty" | ./././hsh 53 | ./././hsh: 1: qwerty: not found 54 | $ 55 | 56 | # List of allowed functions and system calls 57 | access (man 2 access) 58 | chdir (man 2 chdir) 59 | close (man 2 close) 60 | closedir (man 3 closedir) 61 | execve (man 2 execve) 62 | exit (man 3 exit) 63 | _exit (man 2 _exit) 64 | fflush (man 3 fflush) 65 | fork (man 2 fork) 66 | free (man 3 free) 67 | getcwd (man 3 getcwd) 68 | getline (man 3 getline) 69 | getpid (man 2 getpid) 70 | isatty (man 3 isatty) 71 | kill (man 2 kill) 72 | malloc (man 3 malloc) 73 | open (man 2 open) 74 | opendir (man 3 opendir) 75 | perror (man 3 perror) 76 | read (man 2 read) 77 | readdir (man 3 readdir) 78 | signal (man 2 signal) 79 | stat (__xstat) (man 2 stat) 80 | lstat (__lxstat) (man 2 lstat) 81 | fstat (__fxstat) (man 2 fstat) 82 | strtok (man 3 strtok) 83 | wait (man 2 wait) 84 | waitpid (man 2 waitpid) 85 | wait3 (man 2 wait3) 86 | wait4 (man 2 wait4) 87 | write (man 2 write) 88 | 89 | # Compilation 90 | ## Your shell will be compiled this way: 91 | 92 | `gcc -Wall -Werror -Wextra -pedantic -std=gnu89 *.c -o hsh` 93 | 94 | 95 | # files 96 | - README.md - description about the project repo 97 | - man_1_simple_shell - is the man page for the shell we are going to write. 98 | - AUTHORS - file at the root of your repository, listing all individuals having contributed content to the repository. 99 | - main.h - is the header file which contains the standared header file and prototype of o function used in the program. 100 | - main.c - initialize the program with infinite loop by call the prompt function 101 | - prompt.c - it use getline system call to read the input from the user and run infinite loop with fork to keep prompt going. 102 | - special_character - It identiies if the special inputs such as if the frist input is slash,the user typed exit or env... 103 | - string.c -it handles the strings(string length, write string,find string in directory,concatane strings....) 104 | - cmd.c - it finds the command the user entered. 105 | - execute.c - execute the command. 106 | 107 | ## How to add Author file 108 | `Bash script for generating the list of authors in git repo` 109 | ``` 110 | #!/bin/sh 111 | 112 | git shortlog -se \ 113 | | perl -spe 's/^\s+\d+\s+//' \ 114 | | sed -e '/^CommitSyncScript.*$/d' \ 115 | > AUTHORS 116 | ``` 117 | -------------------------------------------------------------------------------- /_atoi.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * interactive - returns true if shell is interactive mode 5 | * @info: struct address 6 | * 7 | * Return: 1 if interactive mode, 0 otherwise 8 | */ 9 | int interactive(info_t *info) 10 | { 11 | return (isatty(STDIN_FILENO) && info->readfd <= 2); 12 | } 13 | 14 | /** 15 | * is_delim - checks if character is a delimeter 16 | * @c: the char to check 17 | * @delim: the delimeter string 18 | * Return: 1 if true, 0 if false 19 | */ 20 | int is_delim(char c, char *delim) 21 | { 22 | while (*delim) 23 | if (*delim++ == c) 24 | return (1); 25 | return (0); 26 | } 27 | 28 | /** 29 | *_isalpha - checks for alphabetic character 30 | *@c: The character to input 31 | *Return: 1 if c is alphabetic, 0 otherwise 32 | */ 33 | 34 | int _isalpha(int c) 35 | { 36 | if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) 37 | return (1); 38 | else 39 | return (0); 40 | } 41 | 42 | /** 43 | *_atoi - converts a string to an integer 44 | *@s: the string to be converted 45 | *Return: 0 if no numbers in string, converted number otherwise 46 | */ 47 | 48 | int _atoi(char *s) 49 | { 50 | int i, sign = 1, flag = 0, output; 51 | unsigned int result = 0; 52 | 53 | for (i = 0; s[i] != '\0' && flag != 2; i++) 54 | { 55 | if (s[i] == '-') 56 | sign *= -1; 57 | 58 | if (s[i] >= '0' && s[i] <= '9') 59 | { 60 | flag = 1; 61 | result *= 10; 62 | result += (s[i] - '0'); 63 | } 64 | else if (flag == 1) 65 | flag = 2; 66 | } 67 | 68 | if (sign == -1) 69 | output = -result; 70 | else 71 | output = result; 72 | 73 | return (output); 74 | } 75 | 76 | -------------------------------------------------------------------------------- /builtin.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _myexit - exits the shell 5 | * @info: Structure containing potential arguments. Used to maintain 6 | * constant function prototype. 7 | * Return: exits with a given exit status 8 | * (0) if info.argv[0] != "exit" 9 | */ 10 | int _myexit(info_t *info) 11 | { 12 | int exitcheck; 13 | 14 | if (info->argv[1]) /* If there is an exit arguement */ 15 | { 16 | exitcheck = _erratoi(info->argv[1]); 17 | if (exitcheck == -1) 18 | { 19 | info->status = 2; 20 | print_error(info, "Illegal number: "); 21 | _eputs(info->argv[1]); 22 | _eputchar('\n'); 23 | return (1); 24 | } 25 | info->err_num = _erratoi(info->argv[1]); 26 | return (-2); 27 | } 28 | info->err_num = -1; 29 | return (-2); 30 | } 31 | 32 | /** 33 | * _mycd - changes the current directory of the process 34 | * @info: Structure containing potential arguments. Used to maintain 35 | * constant function prototype. 36 | * Return: Always 0 37 | */ 38 | int _mycd(info_t *info) 39 | { 40 | char *s, *dir, buffer[1024]; 41 | int chdir_ret; 42 | 43 | s = getcwd(buffer, 1024); 44 | if (!s) 45 | _puts("TODO: >>getcwd failure emsg here<<\n"); 46 | if (!info->argv[1]) 47 | { 48 | dir = _getenv(info, "HOME="); 49 | if (!dir) 50 | chdir_ret = /* TODO: what should this be? */ 51 | chdir((dir = _getenv(info, "PWD=")) ? dir : "/"); 52 | else 53 | chdir_ret = chdir(dir); 54 | } 55 | else if (_strcmp(info->argv[1], "-") == 0) 56 | { 57 | if (!_getenv(info, "OLDPWD=")) 58 | { 59 | _puts(s); 60 | _putchar('\n'); 61 | return (1); 62 | } 63 | _puts(_getenv(info, "OLDPWD=")), _putchar('\n'); 64 | chdir_ret = /* TODO: what should this be? */ 65 | chdir((dir = _getenv(info, "OLDPWD=")) ? dir : "/"); 66 | } 67 | else 68 | chdir_ret = chdir(info->argv[1]); 69 | if (chdir_ret == -1) 70 | { 71 | print_error(info, "can't cd to "); 72 | _eputs(info->argv[1]), _eputchar('\n'); 73 | } 74 | else 75 | { 76 | _setenv(info, "OLDPWD", _getenv(info, "PWD=")); 77 | _setenv(info, "PWD", getcwd(buffer, 1024)); 78 | } 79 | return (0); 80 | } 81 | 82 | /** 83 | * _myhelp - changes the current directory of the process 84 | * @info: Structure containing potential arguments. Used to maintain 85 | * constant function prototype. 86 | * Return: Always 0 87 | */ 88 | int _myhelp(info_t *info) 89 | { 90 | char **arg_array; 91 | 92 | arg_array = info->argv; 93 | _puts("help call works. Function not yet implemented \n"); 94 | if (0) 95 | _puts(*arg_array); /* temp att_unused workaround */ 96 | return (0); 97 | } 98 | -------------------------------------------------------------------------------- /builtin1.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _myhistory - displays the history list, one command by line, preceded 5 | * with line numbers, starting at 0. 6 | * @info: Structure containing potential arguments. Used to maintain 7 | * constant function prototype. 8 | * Return: Always 0 9 | */ 10 | int _myhistory(info_t *info) 11 | { 12 | print_list(info->history); 13 | return (0); 14 | } 15 | 16 | /** 17 | * unset_alias - sets alias to string 18 | * @info: parameter struct 19 | * @str: the string alias 20 | * 21 | * Return: Always 0 on success, 1 on error 22 | */ 23 | int unset_alias(info_t *info, char *str) 24 | { 25 | char *p, c; 26 | int ret; 27 | 28 | p = _strchr(str, '='); 29 | if (!p) 30 | return (1); 31 | c = *p; 32 | *p = 0; 33 | ret = delete_node_at_index(&(info->alias), 34 | get_node_index(info->alias, node_starts_with(info->alias, str, -1))); 35 | *p = c; 36 | return (ret); 37 | } 38 | 39 | /** 40 | * set_alias - sets alias to string 41 | * @info: parameter struct 42 | * @str: the string alias 43 | * 44 | * Return: Always 0 on success, 1 on error 45 | */ 46 | int set_alias(info_t *info, char *str) 47 | { 48 | char *p; 49 | 50 | p = _strchr(str, '='); 51 | if (!p) 52 | return (1); 53 | if (!*++p) 54 | return (unset_alias(info, str)); 55 | 56 | unset_alias(info, str); 57 | return (add_node_end(&(info->alias), str, 0) == NULL); 58 | } 59 | 60 | /** 61 | * print_alias - prints an alias string 62 | * @node: the alias node 63 | * 64 | * Return: Always 0 on success, 1 on error 65 | */ 66 | int print_alias(list_t *node) 67 | { 68 | char *p = NULL, *a = NULL; 69 | 70 | if (node) 71 | { 72 | p = _strchr(node->str, '='); 73 | for (a = node->str; a <= p; a++) 74 | _putchar(*a); 75 | _putchar('\''); 76 | _puts(p + 1); 77 | _puts("'\n"); 78 | return (0); 79 | } 80 | return (1); 81 | } 82 | 83 | /** 84 | * _myalias - mimics the alias builtin (man alias) 85 | * @info: Structure containing potential arguments. Used to maintain 86 | * constant function prototype. 87 | * Return: Always 0 88 | */ 89 | int _myalias(info_t *info) 90 | { 91 | int i = 0; 92 | char *p = NULL; 93 | list_t *node = NULL; 94 | 95 | if (info->argc == 1) 96 | { 97 | node = info->alias; 98 | while (node) 99 | { 100 | print_alias(node); 101 | node = node->next; 102 | } 103 | return (0); 104 | } 105 | for (i = 1; info->argv[i]; i++) 106 | { 107 | p = _strchr(info->argv[i], '='); 108 | if (p) 109 | set_alias(info, info->argv[i]); 110 | else 111 | print_alias(node_starts_with(info->alias, info->argv[i], '=')); 112 | } 113 | 114 | return (0); 115 | } 116 | -------------------------------------------------------------------------------- /environ.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _myenv - prints the current environment 5 | * @info: Structure containing potential arguments. Used to maintain 6 | * constant function prototype. 7 | * Return: Always 0 8 | */ 9 | int _myenv(info_t *info) 10 | { 11 | print_list_str(info->env); 12 | return (0); 13 | } 14 | 15 | /** 16 | * _getenv - gets the value of an environ variable 17 | * @info: Structure containing potential arguments. Used to maintain 18 | * @name: env var name 19 | * 20 | * Return: the value 21 | */ 22 | char *_getenv(info_t *info, const char *name) 23 | { 24 | list_t *node = info->env; 25 | char *p; 26 | 27 | while (node) 28 | { 29 | p = starts_with(node->str, name); 30 | if (p && *p) 31 | return (p); 32 | node = node->next; 33 | } 34 | return (NULL); 35 | } 36 | 37 | /** 38 | * _mysetenv - Initialize a new environment variable, 39 | * or modify an existing one 40 | * @info: Structure containing potential arguments. Used to maintain 41 | * constant function prototype. 42 | * Return: Always 0 43 | */ 44 | int _mysetenv(info_t *info) 45 | { 46 | if (info->argc != 3) 47 | { 48 | _eputs("Incorrect number of arguements\n"); 49 | return (1); 50 | } 51 | if (_setenv(info, info->argv[1], info->argv[2])) 52 | return (0); 53 | return (1); 54 | } 55 | 56 | /** 57 | * _myunsetenv - Remove an environment variable 58 | * @info: Structure containing potential arguments. Used to maintain 59 | * constant function prototype. 60 | * Return: Always 0 61 | */ 62 | int _myunsetenv(info_t *info) 63 | { 64 | int i; 65 | 66 | if (info->argc == 1) 67 | { 68 | _eputs("Too few arguements.\n"); 69 | return (1); 70 | } 71 | for (i = 1; i <= info->argc; i++) 72 | _unsetenv(info, info->argv[i]); 73 | 74 | return (0); 75 | } 76 | 77 | /** 78 | * populate_env_list - populates env linked list 79 | * @info: Structure containing potential arguments. Used to maintain 80 | * constant function prototype. 81 | * Return: Always 0 82 | */ 83 | int populate_env_list(info_t *info) 84 | { 85 | list_t *node = NULL; 86 | size_t i; 87 | 88 | for (i = 0; environ[i]; i++) 89 | add_node_end(&node, environ[i], 0); 90 | info->env = node; 91 | return (0); 92 | } 93 | -------------------------------------------------------------------------------- /errors.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | *_eputs - prints an input string 5 | * @str: the string to be printed 6 | * 7 | * Return: Nothing 8 | */ 9 | void _eputs(char *str) 10 | { 11 | int i = 0; 12 | 13 | if (!str) 14 | return; 15 | while (str[i] != '\0') 16 | { 17 | _eputchar(str[i]); 18 | i++; 19 | } 20 | } 21 | 22 | /** 23 | * _eputchar - writes the character c to stderr 24 | * @c: The character to print 25 | * 26 | * Return: On success 1. 27 | * On error, -1 is returned, and errno is set appropriately. 28 | */ 29 | int _eputchar(char c) 30 | { 31 | static int i; 32 | static char buf[WRITE_BUF_SIZE]; 33 | 34 | if (c == BUF_FLUSH || i >= WRITE_BUF_SIZE) 35 | { 36 | write(2, buf, i); 37 | i = 0; 38 | } 39 | if (c != BUF_FLUSH) 40 | buf[i++] = c; 41 | return (1); 42 | } 43 | 44 | /** 45 | * _putfd - writes the character c to given fd 46 | * @c: The character to print 47 | * @fd: The filedescriptor to write to 48 | * 49 | * Return: On success 1. 50 | * On error, -1 is returned, and errno is set appropriately. 51 | */ 52 | int _putfd(char c, int fd) 53 | { 54 | static int i; 55 | static char buf[WRITE_BUF_SIZE]; 56 | 57 | if (c == BUF_FLUSH || i >= WRITE_BUF_SIZE) 58 | { 59 | write(fd, buf, i); 60 | i = 0; 61 | } 62 | if (c != BUF_FLUSH) 63 | buf[i++] = c; 64 | return (1); 65 | } 66 | 67 | /** 68 | *_putsfd - prints an input string 69 | * @str: the string to be printed 70 | * @fd: the filedescriptor to write to 71 | * 72 | * Return: the number of chars put 73 | */ 74 | int _putsfd(char *str, int fd) 75 | { 76 | int i = 0; 77 | 78 | if (!str) 79 | return (0); 80 | while (*str) 81 | { 82 | i += _putfd(*str++, fd); 83 | } 84 | return (i); 85 | } 86 | -------------------------------------------------------------------------------- /errors1.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * _erratoi - converts a string to an integer 5 | * @s: the string to be converted 6 | * Return: 0 if no numbers in string, converted number otherwise 7 | * -1 on error 8 | */ 9 | int _erratoi(char *s) 10 | { 11 | int i = 0; 12 | unsigned long int result = 0; 13 | 14 | if (*s == '+') 15 | s++; /* TODO: why does this make main return 255? */ 16 | for (i = 0; s[i] != '\0'; i++) 17 | { 18 | if (s[i] >= '0' && s[i] <= '9') 19 | { 20 | result *= 10; 21 | result += (s[i] - '0'); 22 | if (result > INT_MAX) 23 | return (-1); 24 | } 25 | else 26 | return (-1); 27 | } 28 | return (result); 29 | } 30 | 31 | /** 32 | * print_error - prints an error message 33 | * @info: the parameter & return info struct 34 | * @estr: string containing specified error type 35 | * Return: 0 if no numbers in string, converted number otherwise 36 | * -1 on error 37 | */ 38 | void print_error(info_t *info, char *estr) 39 | { 40 | _eputs(info->fname); 41 | _eputs(": "); 42 | print_d(info->line_count, STDERR_FILENO); 43 | _eputs(": "); 44 | _eputs(info->argv[0]); 45 | _eputs(": "); 46 | _eputs(estr); 47 | } 48 | 49 | /** 50 | * print_d - function prints a decimal (integer) number (base 10) 51 | * @input: the input 52 | * @fd: the filedescriptor to write to 53 | * 54 | * Return: number of characters printed 55 | */ 56 | int print_d(int input, int fd) 57 | { 58 | int (*__putchar)(char) = _putchar; 59 | int i, count = 0; 60 | unsigned int _abs_, current; 61 | 62 | if (fd == STDERR_FILENO) 63 | __putchar = _eputchar; 64 | if (input < 0) 65 | { 66 | _abs_ = -input; 67 | __putchar('-'); 68 | count++; 69 | } 70 | else 71 | _abs_ = input; 72 | current = _abs_; 73 | for (i = 1000000000; i > 1; i /= 10) 74 | { 75 | if (_abs_ / i) 76 | { 77 | __putchar('0' + current / i); 78 | count++; 79 | } 80 | current %= i; 81 | } 82 | __putchar('0' + current); 83 | count++; 84 | 85 | return (count); 86 | } 87 | 88 | /** 89 | * convert_number - converter function, a clone of itoa 90 | * @num: number 91 | * @base: base 92 | * @flags: argument flags 93 | * 94 | * Return: string 95 | */ 96 | char *convert_number(long int num, int base, int flags) 97 | { 98 | static char *array; 99 | static char buffer[50]; 100 | char sign = 0; 101 | char *ptr; 102 | unsigned long n = num; 103 | 104 | if (!(flags & CONVERT_UNSIGNED) && num < 0) 105 | { 106 | n = -num; 107 | sign = '-'; 108 | 109 | } 110 | array = flags & CONVERT_LOWERCASE ? "0123456789abcdef" : "0123456789ABCDEF"; 111 | ptr = &buffer[49]; 112 | *ptr = '\0'; 113 | 114 | do { 115 | *--ptr = array[n % base]; 116 | n /= base; 117 | } while (n != 0); 118 | 119 | if (sign) 120 | *--ptr = sign; 121 | return (ptr); 122 | } 123 | 124 | /** 125 | * remove_comments - function replaces first instance of '#' with '\0' 126 | * @buf: address of the string to modify 127 | * 128 | * Return: Always 0; 129 | */ 130 | void remove_comments(char *buf) 131 | { 132 | int i; 133 | 134 | for (i = 0; buf[i] != '\0'; i++) 135 | if (buf[i] == '#' && (!i || buf[i - 1] == ' ')) 136 | { 137 | buf[i] = '\0'; 138 | break; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /exits.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | **_strncpy - copies a string 5 | *@dest: the destination string to be copied to 6 | *@src: the source string 7 | *@n: the amount of characters to be copied 8 | *Return: the concatenated string 9 | */ 10 | char *_strncpy(char *dest, char *src, int n) 11 | { 12 | int i, j; 13 | char *s = dest; 14 | 15 | i = 0; 16 | while (src[i] != '\0' && i < n - 1) 17 | { 18 | dest[i] = src[i]; 19 | i++; 20 | } 21 | if (i < n) 22 | { 23 | j = i; 24 | while (j < n) 25 | { 26 | dest[j] = '\0'; 27 | j++; 28 | } 29 | } 30 | return (s); 31 | } 32 | 33 | /** 34 | **_strncat - concatenates two strings 35 | *@dest: the first string 36 | *@src: the second string 37 | *@n: the amount of bytes to be maximally used 38 | *Return: the concatenated string 39 | */ 40 | char *_strncat(char *dest, char *src, int n) 41 | { 42 | int i, j; 43 | char *s = dest; 44 | 45 | i = 0; 46 | j = 0; 47 | while (dest[i] != '\0') 48 | i++; 49 | while (src[j] != '\0' && j < n) 50 | { 51 | dest[i] = src[j]; 52 | i++; 53 | j++; 54 | } 55 | if (j < n) 56 | dest[i] = '\0'; 57 | return (s); 58 | } 59 | 60 | /** 61 | **_strchr - locates a character in a string 62 | *@s: the string to be parsed 63 | *@c: the character to look for 64 | *Return: (s) a pointer to the memory area s 65 | */ 66 | char *_strchr(char *s, char c) 67 | { 68 | do { 69 | if (*s == c) 70 | return (s); 71 | } while (*s++ != '\0'); 72 | 73 | return (NULL); 74 | } 75 | -------------------------------------------------------------------------------- /getLine.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * input_buf - buffers chained commands 5 | * @info: parameter struct 6 | * @buf: address of buffer 7 | * @len: address of len var 8 | * 9 | * Return: bytes read 10 | */ 11 | ssize_t input_buf(info_t *info, char **buf, size_t *len) 12 | { 13 | ssize_t r = 0; 14 | size_t len_p = 0; 15 | 16 | if (!*len) /* if nothing left in the buffer, fill it */ 17 | { 18 | /*bfree((void **)info->cmd_buf);*/ 19 | free(*buf); 20 | *buf = NULL; 21 | signal(SIGINT, sigintHandler); 22 | #if USE_GETLINE 23 | r = getline(buf, &len_p, stdin); 24 | #else 25 | r = _getline(info, buf, &len_p); 26 | #endif 27 | if (r > 0) 28 | { 29 | if ((*buf)[r - 1] == '\n') 30 | { 31 | (*buf)[r - 1] = '\0'; /* remove trailing newline */ 32 | r--; 33 | } 34 | info->linecount_flag = 1; 35 | remove_comments(*buf); 36 | build_history_list(info, *buf, info->histcount++); 37 | /* if (_strchr(*buf, ';')) is this a command chain? */ 38 | { 39 | *len = r; 40 | info->cmd_buf = buf; 41 | } 42 | } 43 | } 44 | return (r); 45 | } 46 | 47 | /** 48 | * get_input - gets a line minus the newline 49 | * @info: parameter struct 50 | * 51 | * Return: bytes read 52 | */ 53 | ssize_t get_input(info_t *info) 54 | { 55 | static char *buf; /* the ';' command chain buffer */ 56 | static size_t i, j, len; 57 | ssize_t r = 0; 58 | char **buf_p = &(info->arg), *p; 59 | 60 | _putchar(BUF_FLUSH); 61 | r = input_buf(info, &buf, &len); 62 | if (r == -1) /* EOF */ 63 | return (-1); 64 | if (len) /* we have commands left in the chain buffer */ 65 | { 66 | j = i; /* init new iterator to current buf position */ 67 | p = buf + i; /* get pointer for return */ 68 | 69 | check_chain(info, buf, &j, i, len); 70 | while (j < len) /* iterate to semicolon or end */ 71 | { 72 | if (is_chain(info, buf, &j)) 73 | break; 74 | j++; 75 | } 76 | 77 | i = j + 1; /* increment past nulled ';'' */ 78 | if (i >= len) /* reached end of buffer? */ 79 | { 80 | i = len = 0; /* reset position and length */ 81 | info->cmd_buf_type = CMD_NORM; 82 | } 83 | 84 | *buf_p = p; /* pass back pointer to current command position */ 85 | return (_strlen(p)); /* return length of current command */ 86 | } 87 | 88 | *buf_p = buf; /* else not a chain, pass back buffer from _getline() */ 89 | return (r); /* return length of buffer from _getline() */ 90 | } 91 | 92 | /** 93 | * read_buf - reads a buffer 94 | * @info: parameter struct 95 | * @buf: buffer 96 | * @i: size 97 | * 98 | * Return: r 99 | */ 100 | ssize_t read_buf(info_t *info, char *buf, size_t *i) 101 | { 102 | ssize_t r = 0; 103 | 104 | if (*i) 105 | return (0); 106 | r = read(info->readfd, buf, READ_BUF_SIZE); 107 | if (r >= 0) 108 | *i = r; 109 | return (r); 110 | } 111 | 112 | /** 113 | * _getline - gets the next line of input from STDIN 114 | * @info: parameter struct 115 | * @ptr: address of pointer to buffer, preallocated or NULL 116 | * @length: size of preallocated ptr buffer if not NULL 117 | * 118 | * Return: s 119 | */ 120 | int _getline(info_t *info, char **ptr, size_t *length) 121 | { 122 | static char buf[READ_BUF_SIZE]; 123 | static size_t i, len; 124 | size_t k; 125 | ssize_t r = 0, s = 0; 126 | char *p = NULL, *new_p = NULL, *c; 127 | 128 | p = *ptr; 129 | if (p && length) 130 | s = *length; 131 | if (i == len) 132 | i = len = 0; 133 | 134 | r = read_buf(info, buf, &len); 135 | if (r == -1 || (r == 0 && len == 0)) 136 | return (-1); 137 | 138 | c = _strchr(buf + i, '\n'); 139 | k = c ? 1 + (unsigned int)(c - buf) : len; 140 | new_p = _realloc(p, s, s ? s + k : k + 1); 141 | if (!new_p) /* MALLOC FAILURE! */ 142 | return (p ? free(p), -1 : -1); 143 | 144 | if (s) 145 | _strncat(new_p, buf + i, k - i); 146 | else 147 | _strncpy(new_p, buf + i, k - i + 1); 148 | 149 | s += k - i; 150 | i = k; 151 | p = new_p; 152 | 153 | if (length) 154 | *length = s; 155 | *ptr = p; 156 | return (s); 157 | } 158 | 159 | /** 160 | * sigintHandler - blocks ctrl-C 161 | * @sig_num: the signal number 162 | * 163 | * Return: void 164 | */ 165 | void sigintHandler(__attribute__((unused))int sig_num) 166 | { 167 | _puts("\n"); 168 | _puts("$ "); 169 | _putchar(BUF_FLUSH); 170 | } 171 | -------------------------------------------------------------------------------- /getenv.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * get_environ - returns the string array copy of our environ 5 | * @info: Structure containing potential arguments. Used to maintain 6 | * constant function prototype. 7 | * Return: Always 0 8 | */ 9 | char **get_environ(info_t *info) 10 | { 11 | if (!info->environ || info->env_changed) 12 | { 13 | info->environ = list_to_strings(info->env); 14 | info->env_changed = 0; 15 | } 16 | 17 | return (info->environ); 18 | } 19 | 20 | /** 21 | * _unsetenv - Remove an environment variable 22 | * @info: Structure containing potential arguments. Used to maintain 23 | * constant function prototype. 24 | * Return: 1 on delete, 0 otherwise 25 | * @var: the string env var property 26 | */ 27 | int _unsetenv(info_t *info, char *var) 28 | { 29 | list_t *node = info->env; 30 | size_t i = 0; 31 | char *p; 32 | 33 | if (!node || !var) 34 | return (0); 35 | 36 | while (node) 37 | { 38 | p = starts_with(node->str, var); 39 | if (p && *p == '=') 40 | { 41 | info->env_changed = delete_node_at_index(&(info->env), i); 42 | i = 0; 43 | node = info->env; 44 | continue; 45 | } 46 | node = node->next; 47 | i++; 48 | } 49 | return (info->env_changed); 50 | } 51 | 52 | /** 53 | * _setenv - Initialize a new environment variable, 54 | * or modify an existing one 55 | * @info: Structure containing potential arguments. Used to maintain 56 | * constant function prototype. 57 | * @var: the string env var property 58 | * @value: the string env var value 59 | * Return: Always 0 60 | */ 61 | int _setenv(info_t *info, char *var, char *value) 62 | { 63 | char *buf = NULL; 64 | list_t *node; 65 | char *p; 66 | 67 | if (!var || !value) 68 | return (0); 69 | 70 | buf = malloc(_strlen(var) + _strlen(value) + 2); 71 | if (!buf) 72 | return (1); 73 | _strcpy(buf, var); 74 | _strcat(buf, "="); 75 | _strcat(buf, value); 76 | node = info->env; 77 | while (node) 78 | { 79 | p = starts_with(node->str, var); 80 | if (p && *p == '=') 81 | { 82 | free(node->str); 83 | node->str = buf; 84 | info->env_changed = 1; 85 | return (0); 86 | } 87 | node = node->next; 88 | } 89 | add_node_end(&(info->env), buf, 0); 90 | free(buf); 91 | info->env_changed = 1; 92 | return (0); 93 | } 94 | -------------------------------------------------------------------------------- /getinfo.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * clear_info - initializes info_t struct 5 | * @info: struct address 6 | */ 7 | void clear_info(info_t *info) 8 | { 9 | info->arg = NULL; 10 | info->argv = NULL; 11 | info->path = NULL; 12 | info->argc = 0; 13 | } 14 | 15 | /** 16 | * set_info - initializes info_t struct 17 | * @info: struct address 18 | * @av: argument vector 19 | */ 20 | void set_info(info_t *info, char **av) 21 | { 22 | int i = 0; 23 | 24 | info->fname = av[0]; 25 | if (info->arg) 26 | { 27 | info->argv = strtow(info->arg, " \t"); 28 | if (!info->argv) 29 | { 30 | 31 | info->argv = malloc(sizeof(char *) * 2); 32 | if (info->argv) 33 | { 34 | info->argv[0] = _strdup(info->arg); 35 | info->argv[1] = NULL; 36 | } 37 | } 38 | for (i = 0; info->argv && info->argv[i]; i++) 39 | ; 40 | info->argc = i; 41 | 42 | replace_alias(info); 43 | replace_vars(info); 44 | } 45 | } 46 | 47 | /** 48 | * free_info - frees info_t struct fields 49 | * @info: struct address 50 | * @all: true if freeing all fields 51 | */ 52 | void free_info(info_t *info, int all) 53 | { 54 | ffree(info->argv); 55 | info->argv = NULL; 56 | info->path = NULL; 57 | if (all) 58 | { 59 | if (!info->cmd_buf) 60 | free(info->arg); 61 | if (info->env) 62 | free_list(&(info->env)); 63 | if (info->history) 64 | free_list(&(info->history)); 65 | if (info->alias) 66 | free_list(&(info->alias)); 67 | ffree(info->environ); 68 | info->environ = NULL; 69 | bfree((void **)info->cmd_buf); 70 | if (info->readfd > 2) 71 | close(info->readfd); 72 | _putchar(BUF_FLUSH); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /history.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * get_history_file - gets the history file 5 | * @info: parameter struct 6 | * 7 | * Return: allocated string containg history file 8 | */ 9 | 10 | char *get_history_file(info_t *info) 11 | { 12 | char *buf, *dir; 13 | 14 | dir = _getenv(info, "HOME="); 15 | if (!dir) 16 | return (NULL); 17 | buf = malloc(sizeof(char) * (_strlen(dir) + _strlen(HIST_FILE) + 2)); 18 | if (!buf) 19 | return (NULL); 20 | buf[0] = 0; 21 | _strcpy(buf, dir); 22 | _strcat(buf, "/"); 23 | _strcat(buf, HIST_FILE); 24 | return (buf); 25 | } 26 | 27 | /** 28 | * write_history - creates a file, or appends to an existing file 29 | * @info: the parameter struct 30 | * 31 | * Return: 1 on success, else -1 32 | */ 33 | int write_history(info_t *info) 34 | { 35 | ssize_t fd; 36 | char *filename = get_history_file(info); 37 | list_t *node = NULL; 38 | 39 | if (!filename) 40 | return (-1); 41 | 42 | fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0644); 43 | free(filename); 44 | if (fd == -1) 45 | return (-1); 46 | for (node = info->history; node; node = node->next) 47 | { 48 | _putsfd(node->str, fd); 49 | _putfd('\n', fd); 50 | } 51 | _putfd(BUF_FLUSH, fd); 52 | close(fd); 53 | return (1); 54 | } 55 | 56 | /** 57 | * read_history - reads history from file 58 | * @info: the parameter struct 59 | * 60 | * Return: histcount on success, 0 otherwise 61 | */ 62 | int read_history(info_t *info) 63 | { 64 | int i, last = 0, linecount = 0; 65 | ssize_t fd, rdlen, fsize = 0; 66 | struct stat st; 67 | char *buf = NULL, *filename = get_history_file(info); 68 | 69 | if (!filename) 70 | return (0); 71 | 72 | fd = open(filename, O_RDONLY); 73 | free(filename); 74 | if (fd == -1) 75 | return (0); 76 | if (!fstat(fd, &st)) 77 | fsize = st.st_size; 78 | if (fsize < 2) 79 | return (0); 80 | buf = malloc(sizeof(char) * (fsize + 1)); 81 | if (!buf) 82 | return (0); 83 | rdlen = read(fd, buf, fsize); 84 | buf[fsize] = 0; 85 | if (rdlen <= 0) 86 | return (free(buf), 0); 87 | close(fd); 88 | for (i = 0; i < fsize; i++) 89 | if (buf[i] == '\n') 90 | { 91 | buf[i] = 0; 92 | build_history_list(info, buf + last, linecount++); 93 | last = i + 1; 94 | } 95 | if (last != i) 96 | build_history_list(info, buf + last, linecount++); 97 | free(buf); 98 | info->histcount = linecount; 99 | while (info->histcount-- >= HIST_MAX) 100 | delete_node_at_index(&(info->history), 0); 101 | renumber_history(info); 102 | return (info->histcount); 103 | } 104 | 105 | /** 106 | * build_history_list - adds entry to a history linked list 107 | * @info: Structure containing potential arguments. Used to maintain 108 | * @buf: buffer 109 | * @linecount: the history linecount, histcount 110 | * 111 | * Return: Always 0 112 | */ 113 | int build_history_list(info_t *info, char *buf, int linecount) 114 | { 115 | list_t *node = NULL; 116 | 117 | if (info->history) 118 | node = info->history; 119 | add_node_end(&node, buf, linecount); 120 | 121 | if (!info->history) 122 | info->history = node; 123 | return (0); 124 | } 125 | 126 | /** 127 | * renumber_history - renumbers the history linked list after changes 128 | * @info: Structure containing potential arguments. Used to maintain 129 | * 130 | * Return: the new histcount 131 | */ 132 | int renumber_history(info_t *info) 133 | { 134 | list_t *node = info->history; 135 | int i = 0; 136 | 137 | while (node) 138 | { 139 | node->num = i++; 140 | node = node->next; 141 | } 142 | return (info->histcount = i); 143 | } 144 | -------------------------------------------------------------------------------- /lists.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * add_node - adds a node to the start of the list 5 | * @head: address of pointer to head node 6 | * @str: str field of node 7 | * @num: node index used by history 8 | * 9 | * Return: size of list 10 | */ 11 | list_t *add_node(list_t **head, const char *str, int num) 12 | { 13 | list_t *new_head; 14 | 15 | if (!head) 16 | return (NULL); 17 | new_head = malloc(sizeof(list_t)); 18 | if (!new_head) 19 | return (NULL); 20 | _memset((void *)new_head, 0, sizeof(list_t)); 21 | new_head->num = num; 22 | if (str) 23 | { 24 | new_head->str = _strdup(str); 25 | if (!new_head->str) 26 | { 27 | free(new_head); 28 | return (NULL); 29 | } 30 | } 31 | new_head->next = *head; 32 | *head = new_head; 33 | return (new_head); 34 | } 35 | 36 | /** 37 | * add_node_end - adds a node to the end of the list 38 | * @head: address of pointer to head node 39 | * @str: str field of node 40 | * @num: node index used by history 41 | * 42 | * Return: size of list 43 | */ 44 | list_t *add_node_end(list_t **head, const char *str, int num) 45 | { 46 | list_t *new_node, *node; 47 | 48 | if (!head) 49 | return (NULL); 50 | 51 | node = *head; 52 | new_node = malloc(sizeof(list_t)); 53 | if (!new_node) 54 | return (NULL); 55 | _memset((void *)new_node, 0, sizeof(list_t)); 56 | new_node->num = num; 57 | if (str) 58 | { 59 | new_node->str = _strdup(str); 60 | if (!new_node->str) 61 | { 62 | free(new_node); 63 | return (NULL); 64 | } 65 | } 66 | if (node) 67 | { 68 | while (node->next) 69 | node = node->next; 70 | node->next = new_node; 71 | } 72 | else 73 | *head = new_node; 74 | return (new_node); 75 | } 76 | 77 | /** 78 | * print_list_str - prints only the str element of a list_t linked list 79 | * @h: pointer to first node 80 | * 81 | * Return: size of list 82 | */ 83 | size_t print_list_str(const list_t *h) 84 | { 85 | size_t i = 0; 86 | 87 | while (h) 88 | { 89 | _puts(h->str ? h->str : "(nil)"); 90 | _puts("\n"); 91 | h = h->next; 92 | i++; 93 | } 94 | return (i); 95 | } 96 | 97 | /** 98 | * delete_node_at_index - deletes node at given index 99 | * @head: address of pointer to first node 100 | * @index: index of node to delete 101 | * 102 | * Return: 1 on success, 0 on failure 103 | */ 104 | int delete_node_at_index(list_t **head, unsigned int index) 105 | { 106 | list_t *node, *prev_node; 107 | unsigned int i = 0; 108 | 109 | if (!head || !*head) 110 | return (0); 111 | 112 | if (!index) 113 | { 114 | node = *head; 115 | *head = (*head)->next; 116 | free(node->str); 117 | free(node); 118 | return (1); 119 | } 120 | node = *head; 121 | while (node) 122 | { 123 | if (i == index) 124 | { 125 | prev_node->next = node->next; 126 | free(node->str); 127 | free(node); 128 | return (1); 129 | } 130 | i++; 131 | prev_node = node; 132 | node = node->next; 133 | } 134 | return (0); 135 | } 136 | 137 | /** 138 | * free_list - frees all nodes of a list 139 | * @head_ptr: address of pointer to head node 140 | * 141 | * Return: void 142 | */ 143 | void free_list(list_t **head_ptr) 144 | { 145 | list_t *node, *next_node, *head; 146 | 147 | if (!head_ptr || !*head_ptr) 148 | return; 149 | head = *head_ptr; 150 | node = head; 151 | while (node) 152 | { 153 | next_node = node->next; 154 | free(node->str); 155 | free(node); 156 | node = next_node; 157 | } 158 | *head_ptr = NULL; 159 | } 160 | -------------------------------------------------------------------------------- /lists1.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * list_len - determines length of linked list 5 | * @h: pointer to first node 6 | * 7 | * Return: size of list 8 | */ 9 | size_t list_len(const list_t *h) 10 | { 11 | size_t i = 0; 12 | 13 | while (h) 14 | { 15 | h = h->next; 16 | i++; 17 | } 18 | return (i); 19 | } 20 | 21 | /** 22 | * list_to_strings - returns an array of strings of the list->str 23 | * @head: pointer to first node 24 | * 25 | * Return: array of strings 26 | */ 27 | char **list_to_strings(list_t *head) 28 | { 29 | list_t *node = head; 30 | size_t i = list_len(head), j; 31 | char **strs; 32 | char *str; 33 | 34 | if (!head || !i) 35 | return (NULL); 36 | strs = malloc(sizeof(char *) * (i + 1)); 37 | if (!strs) 38 | return (NULL); 39 | for (i = 0; node; node = node->next, i++) 40 | { 41 | str = malloc(_strlen(node->str) + 1); 42 | if (!str) 43 | { 44 | for (j = 0; j < i; j++) 45 | free(strs[j]); 46 | free(strs); 47 | return (NULL); 48 | } 49 | 50 | str = _strcpy(str, node->str); 51 | strs[i] = str; 52 | } 53 | strs[i] = NULL; 54 | return (strs); 55 | } 56 | 57 | 58 | /** 59 | * print_list - prints all elements of a list_t linked list 60 | * @h: pointer to first node 61 | * 62 | * Return: size of list 63 | */ 64 | size_t print_list(const list_t *h) 65 | { 66 | size_t i = 0; 67 | 68 | while (h) 69 | { 70 | _puts(convert_number(h->num, 10, 0)); 71 | _putchar(':'); 72 | _putchar(' '); 73 | _puts(h->str ? h->str : "(nil)"); 74 | _puts("\n"); 75 | h = h->next; 76 | i++; 77 | } 78 | return (i); 79 | } 80 | 81 | /** 82 | * node_starts_with - returns node whose string starts with prefix 83 | * @node: pointer to list head 84 | * @prefix: string to match 85 | * @c: the next character after prefix to match 86 | * 87 | * Return: match node or null 88 | */ 89 | list_t *node_starts_with(list_t *node, char *prefix, char c) 90 | { 91 | char *p = NULL; 92 | 93 | while (node) 94 | { 95 | p = starts_with(node->str, prefix); 96 | if (p && ((c == -1) || (*p == c))) 97 | return (node); 98 | node = node->next; 99 | } 100 | return (NULL); 101 | } 102 | 103 | /** 104 | * get_node_index - gets the index of a node 105 | * @head: pointer to list head 106 | * @node: pointer to the node 107 | * 108 | * Return: index of node or -1 109 | */ 110 | ssize_t get_node_index(list_t *head, list_t *node) 111 | { 112 | size_t i = 0; 113 | 114 | while (head) 115 | { 116 | if (head == node) 117 | return (i); 118 | head = head->next; 119 | i++; 120 | } 121 | return (-1); 122 | } 123 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * main - entry point 5 | * @ac: arg count 6 | * @av: arg vector 7 | * 8 | * Return: 0 on success, 1 on error 9 | */ 10 | int main(int ac, char **av) 11 | { 12 | info_t info[] = { INFO_INIT }; 13 | int fd = 2; 14 | 15 | asm ("mov %1, %0\n\t" 16 | "add $3, %0" 17 | : "=r" (fd) 18 | : "r" (fd)); 19 | 20 | if (ac == 2) 21 | { 22 | fd = open(av[1], O_RDONLY); 23 | if (fd == -1) 24 | { 25 | if (errno == EACCES) 26 | exit(126); 27 | if (errno == ENOENT) 28 | { 29 | _eputs(av[0]); 30 | _eputs(": 0: Can't open "); 31 | _eputs(av[1]); 32 | _eputchar('\n'); 33 | _eputchar(BUF_FLUSH); 34 | exit(127); 35 | } 36 | return (EXIT_FAILURE); 37 | } 38 | info->readfd = fd; 39 | } 40 | populate_env_list(info); 41 | read_history(info); 42 | hsh(info, av); 43 | return (EXIT_SUCCESS); 44 | } 45 | -------------------------------------------------------------------------------- /man_1_simple_shell: -------------------------------------------------------------------------------- 1 | .TH man 1 "16 Nov 2022" "0.1" "simple_shell man page" 2 | 3 | .SH NAME 4 | .B simple_shell 5 | - Simple shell create in C to interact with a linux operating system. 6 | 7 | .SH SYNOPSIS 8 | hsh [options] [file] 9 | 10 | .SH DESCRIPTION 11 | Shell is a UNIX term for the interactive user interface with an operating system. The shell is the layer of programming that understands 12 | and executes the commands a user enters. In some systems, the shell is called a command interpreter. A shell usually implies an interface 13 | with a command syntax 14 | 15 | .B Overview 16 | 17 | The simple shell is a command that reads lines from either a file or the terminal, interprets them, and generally executes other commands. It is the program that is started when a user logs into the system. It incorporates many features to aid interactive use and has the advantage that the interpretative language is common to both interactive and non-interactive use (shell scripts). That is, commands can be typed directly to the running simple shell or can be put into a file, which can be executed directly by the simple shell. 18 | .SH Return Value 19 | 20 | Always 0 for success, other number means failure. 21 | 22 | .SH PATH 23 | 24 | It will look inside al directions in PATH env variable for executable. 25 | 26 | .SH 27 | 28 | .SH OPTIONS 29 | .B simple_shell 30 | Command options will be typed after the main command followed by a space and a 31 | '-' symbol. 32 | 33 | .SH EXAMPLE 34 | 35 | [command] [options] 36 | $ ls -l 37 | 38 | .SH BUGS 39 | Single space required after argument. 40 | 41 | 42 | .SH AUTHOR 43 | Godswill Kalu, Vatalis Ibeh. 44 | -------------------------------------------------------------------------------- /memory.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * bfree - frees a pointer and NULLs the address 5 | * @ptr: address of the pointer to free 6 | * 7 | * Return: 1 if freed, otherwise 0. 8 | */ 9 | int bfree(void **ptr) 10 | { 11 | if (ptr && *ptr) 12 | { 13 | free(*ptr); 14 | *ptr = NULL; 15 | return (1); 16 | } 17 | return (0); 18 | } 19 | -------------------------------------------------------------------------------- /parser.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * is_cmd - determines if a file is an executable command 5 | * @info: the info struct 6 | * @path: path to the file 7 | * 8 | * Return: 1 if true, 0 otherwise 9 | */ 10 | int is_cmd(info_t *info, char *path) 11 | { 12 | struct stat st; 13 | 14 | (void)info; 15 | if (!path || stat(path, &st)) 16 | return (0); 17 | 18 | if (st.st_mode & S_IFREG) 19 | { 20 | return (1); 21 | } 22 | return (0); 23 | } 24 | 25 | /** 26 | * dup_chars - duplicates characters 27 | * @pathstr: the PATH string 28 | * @start: starting index 29 | * @stop: stopping index 30 | * 31 | * Return: pointer to new buffer 32 | */ 33 | char *dup_chars(char *pathstr, int start, int stop) 34 | { 35 | static char buf[1024]; 36 | int i = 0, k = 0; 37 | 38 | for (k = 0, i = start; i < stop; i++) 39 | if (pathstr[i] != ':') 40 | buf[k++] = pathstr[i]; 41 | buf[k] = 0; 42 | return (buf); 43 | } 44 | 45 | /** 46 | * find_path - finds this cmd in the PATH string 47 | * @info: the info struct 48 | * @pathstr: the PATH string 49 | * @cmd: the cmd to find 50 | * 51 | * Return: full path of cmd if found or NULL 52 | */ 53 | char *find_path(info_t *info, char *pathstr, char *cmd) 54 | { 55 | int i = 0, curr_pos = 0; 56 | char *path; 57 | 58 | if (!pathstr) 59 | return (NULL); 60 | if ((_strlen(cmd) > 2) && starts_with(cmd, "./")) 61 | { 62 | if (is_cmd(info, cmd)) 63 | return (cmd); 64 | } 65 | while (1) 66 | { 67 | if (!pathstr[i] || pathstr[i] == ':') 68 | { 69 | path = dup_chars(pathstr, curr_pos, i); 70 | if (!*path) 71 | _strcat(path, cmd); 72 | else 73 | { 74 | _strcat(path, "/"); 75 | _strcat(path, cmd); 76 | } 77 | if (is_cmd(info, path)) 78 | return (path); 79 | if (!pathstr[i]) 80 | break; 81 | curr_pos = i; 82 | } 83 | i++; 84 | } 85 | return (NULL); 86 | } 87 | -------------------------------------------------------------------------------- /realloc.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | **_memset - fills memory with a constant byte 5 | *@s: the pointer to the memory area 6 | *@b: the byte to fill *s with 7 | *@n: the amount of bytes to be filled 8 | *Return: (s) a pointer to the memory area s 9 | */ 10 | char *_memset(char *s, char b, unsigned int n) 11 | { 12 | unsigned int i; 13 | 14 | for (i = 0; i < n; i++) 15 | s[i] = b; 16 | return (s); 17 | } 18 | 19 | /** 20 | * ffree - frees a string of strings 21 | * @pp: string of strings 22 | */ 23 | void ffree(char **pp) 24 | { 25 | char **a = pp; 26 | 27 | if (!pp) 28 | return; 29 | while (*pp) 30 | free(*pp++); 31 | free(a); 32 | } 33 | 34 | /** 35 | * _realloc - reallocates a block of memory 36 | * @ptr: pointer to previous malloc'ated block 37 | * @old_size: byte size of previous block 38 | * @new_size: byte size of new block 39 | * 40 | * Return: pointer to da ol'block nameen. 41 | */ 42 | void *_realloc(void *ptr, unsigned int old_size, unsigned int new_size) 43 | { 44 | char *p; 45 | 46 | if (!ptr) 47 | return (malloc(new_size)); 48 | if (!new_size) 49 | return (free(ptr), NULL); 50 | if (new_size == old_size) 51 | return (ptr); 52 | 53 | p = malloc(new_size); 54 | if (!p) 55 | return (NULL); 56 | 57 | old_size = old_size < new_size ? old_size : new_size; 58 | while (old_size--) 59 | p[old_size] = ((char *)ptr)[old_size]; 60 | free(ptr); 61 | return (p); 62 | } 63 | -------------------------------------------------------------------------------- /shell.h: -------------------------------------------------------------------------------- 1 | #ifndef _SHELL_H_ 2 | #define _SHELL_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /* for read/write buffers */ 16 | #define READ_BUF_SIZE 1024 17 | #define WRITE_BUF_SIZE 1024 18 | #define BUF_FLUSH -1 19 | 20 | /* for command chaining */ 21 | #define CMD_NORM 0 22 | #define CMD_OR 1 23 | #define CMD_AND 2 24 | #define CMD_CHAIN 3 25 | 26 | /* for convert_number() */ 27 | #define CONVERT_LOWERCASE 1 28 | #define CONVERT_UNSIGNED 2 29 | 30 | /* 1 if using system getline() */ 31 | #define USE_GETLINE 0 32 | #define USE_STRTOK 0 33 | 34 | #define HIST_FILE ".simple_shell_history" 35 | #define HIST_MAX 4096 36 | 37 | extern char **environ; 38 | 39 | 40 | /** 41 | * struct liststr - singly linked list 42 | * @num: the number field 43 | * @str: a string 44 | * @next: points to the next node 45 | */ 46 | typedef struct liststr 47 | { 48 | int num; 49 | char *str; 50 | struct liststr *next; 51 | } list_t; 52 | 53 | /** 54 | *struct passinfo - contains pseudo-arguements to pass into a function, 55 | * allowing uniform prototype for function pointer struct 56 | *@arg: a string generated from getline containing arguements 57 | *@argv: an array of strings generated from arg 58 | *@path: a string path for the current command 59 | *@argc: the argument count 60 | *@line_count: the error count 61 | *@err_num: the error code for exit()s 62 | *@linecount_flag: if on count this line of input 63 | *@fname: the program filename 64 | *@env: linked list local copy of environ 65 | *@environ: custom modified copy of environ from LL env 66 | *@history: the history node 67 | *@alias: the alias node 68 | *@env_changed: on if environ was changed 69 | *@status: the return status of the last exec'd command 70 | *@cmd_buf: address of pointer to cmd_buf, on if chaining 71 | *@cmd_buf_type: CMD_type ||, &&, ; 72 | *@readfd: the fd from which to read line input 73 | *@histcount: the history line number count 74 | */ 75 | typedef struct passinfo 76 | { 77 | char *arg; 78 | char **argv; 79 | char *path; 80 | int argc; 81 | unsigned int line_count; 82 | int err_num; 83 | int linecount_flag; 84 | char *fname; 85 | list_t *env; 86 | list_t *history; 87 | list_t *alias; 88 | char **environ; 89 | int env_changed; 90 | int status; 91 | 92 | char **cmd_buf; /* pointer to cmd ; chain buffer, for memory mangement */ 93 | int cmd_buf_type; /* CMD_type ||, &&, ; */ 94 | int readfd; 95 | int histcount; 96 | } info_t; 97 | 98 | #define INFO_INIT \ 99 | {NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, \ 100 | 0, 0, 0} 101 | 102 | /** 103 | *struct builtin - contains a builtin string and related function 104 | *@type: the builtin command flag 105 | *@func: the function 106 | */ 107 | typedef struct builtin 108 | { 109 | char *type; 110 | int (*func)(info_t *); 111 | } builtin_table; 112 | 113 | 114 | /* toem_shloop.c */ 115 | int hsh(info_t *, char **); 116 | int find_builtin(info_t *); 117 | void find_cmd(info_t *); 118 | void fork_cmd(info_t *); 119 | 120 | /* toem_parser.c */ 121 | int is_cmd(info_t *, char *); 122 | char *dup_chars(char *, int, int); 123 | char *find_path(info_t *, char *, char *); 124 | 125 | /* loophsh.c */ 126 | int loophsh(char **); 127 | 128 | /* toem_errors.c */ 129 | void _eputs(char *); 130 | int _eputchar(char); 131 | int _putfd(char c, int fd); 132 | int _putsfd(char *str, int fd); 133 | 134 | /* toem_string.c */ 135 | int _strlen(char *); 136 | int _strcmp(char *, char *); 137 | char *starts_with(const char *, const char *); 138 | char *_strcat(char *, char *); 139 | 140 | /* toem_string1.c */ 141 | char *_strcpy(char *, char *); 142 | char *_strdup(const char *); 143 | void _puts(char *); 144 | int _putchar(char); 145 | 146 | /* toem_exits.c */ 147 | char *_strncpy(char *, char *, int); 148 | char *_strncat(char *, char *, int); 149 | char *_strchr(char *, char); 150 | 151 | /* toem_tokenizer.c */ 152 | char **strtow(char *, char *); 153 | char **strtow2(char *, char); 154 | 155 | /* toem_realloc.c */ 156 | char *_memset(char *, char, unsigned int); 157 | void ffree(char **); 158 | void *_realloc(void *, unsigned int, unsigned int); 159 | 160 | /* toem_memory.c */ 161 | int bfree(void **); 162 | 163 | /* toem_atoi.c */ 164 | int interactive(info_t *); 165 | int is_delim(char, char *); 166 | int _isalpha(int); 167 | int _atoi(char *); 168 | 169 | /* toem_errors1.c */ 170 | int _erratoi(char *); 171 | void print_error(info_t *, char *); 172 | int print_d(int, int); 173 | char *convert_number(long int, int, int); 174 | void remove_comments(char *); 175 | 176 | /* toem_builtin.c */ 177 | int _myexit(info_t *); 178 | int _mycd(info_t *); 179 | int _myhelp(info_t *); 180 | 181 | /* toem_builtin1.c */ 182 | int _myhistory(info_t *); 183 | int _myalias(info_t *); 184 | 185 | /*toem_getline.c */ 186 | ssize_t get_input(info_t *); 187 | int _getline(info_t *, char **, size_t *); 188 | void sigintHandler(int); 189 | 190 | /* toem_getinfo.c */ 191 | void clear_info(info_t *); 192 | void set_info(info_t *, char **); 193 | void free_info(info_t *, int); 194 | 195 | /* toem_environ.c */ 196 | char *_getenv(info_t *, const char *); 197 | int _myenv(info_t *); 198 | int _mysetenv(info_t *); 199 | int _myunsetenv(info_t *); 200 | int populate_env_list(info_t *); 201 | 202 | /* toem_getenv.c */ 203 | char **get_environ(info_t *); 204 | int _unsetenv(info_t *, char *); 205 | int _setenv(info_t *, char *, char *); 206 | 207 | /* toem_history.c */ 208 | char *get_history_file(info_t *info); 209 | int write_history(info_t *info); 210 | int read_history(info_t *info); 211 | int build_history_list(info_t *info, char *buf, int linecount); 212 | int renumber_history(info_t *info); 213 | 214 | /* toem_lists.c */ 215 | list_t *add_node(list_t **, const char *, int); 216 | list_t *add_node_end(list_t **, const char *, int); 217 | size_t print_list_str(const list_t *); 218 | int delete_node_at_index(list_t **, unsigned int); 219 | void free_list(list_t **); 220 | 221 | /* toem_lists1.c */ 222 | size_t list_len(const list_t *); 223 | char **list_to_strings(list_t *); 224 | size_t print_list(const list_t *); 225 | list_t *node_starts_with(list_t *, char *, char); 226 | ssize_t get_node_index(list_t *, list_t *); 227 | 228 | /* toem_vars.c */ 229 | int is_chain(info_t *, char *, size_t *); 230 | void check_chain(info_t *, char *, size_t *, size_t, size_t); 231 | int replace_alias(info_t *); 232 | int replace_vars(info_t *); 233 | int replace_string(char **, char *); 234 | 235 | #endif 236 | -------------------------------------------------------------------------------- /shell_loop.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * hsh - main shell loop 5 | * @info: the parameter & return info struct 6 | * @av: the argument vector from main() 7 | * 8 | * Return: 0 on success, 1 on error, or error code 9 | */ 10 | int hsh(info_t *info, char **av) 11 | { 12 | ssize_t r = 0; 13 | int builtin_ret = 0; 14 | 15 | while (r != -1 && builtin_ret != -2) 16 | { 17 | clear_info(info); 18 | if (interactive(info)) 19 | _puts("$ "); 20 | _eputchar(BUF_FLUSH); 21 | r = get_input(info); 22 | if (r != -1) 23 | { 24 | set_info(info, av); 25 | builtin_ret = find_builtin(info); 26 | if (builtin_ret == -1) 27 | find_cmd(info); 28 | } 29 | else if (interactive(info)) 30 | _putchar('\n'); 31 | free_info(info, 0); 32 | } 33 | write_history(info); 34 | free_info(info, 1); 35 | if (!interactive(info) && info->status) 36 | exit(info->status); 37 | if (builtin_ret == -2) 38 | { 39 | if (info->err_num == -1) 40 | exit(info->status); 41 | exit(info->err_num); 42 | } 43 | return (builtin_ret); 44 | } 45 | 46 | /** 47 | * find_builtin - finds a builtin command 48 | * @info: the parameter & return info struct 49 | * 50 | * Return: -1 if builtin not found, 51 | * 0 if builtin executed successfully, 52 | * 1 if builtin found but not successful, 53 | * -2 if builtin signals exit() 54 | */ 55 | int find_builtin(info_t *info) 56 | { 57 | int i, built_in_ret = -1; 58 | builtin_table builtintbl[] = { 59 | {"exit", _myexit}, 60 | {"env", _myenv}, 61 | {"help", _myhelp}, 62 | {"history", _myhistory}, 63 | {"setenv", _mysetenv}, 64 | {"unsetenv", _myunsetenv}, 65 | {"cd", _mycd}, 66 | {"alias", _myalias}, 67 | {NULL, NULL} 68 | }; 69 | 70 | for (i = 0; builtintbl[i].type; i++) 71 | if (_strcmp(info->argv[0], builtintbl[i].type) == 0) 72 | { 73 | info->line_count++; 74 | built_in_ret = builtintbl[i].func(info); 75 | break; 76 | } 77 | return (built_in_ret); 78 | } 79 | 80 | /** 81 | * find_cmd - finds a command in PATH 82 | * @info: the parameter & return info struct 83 | * 84 | * Return: void 85 | */ 86 | void find_cmd(info_t *info) 87 | { 88 | char *path = NULL; 89 | int i, k; 90 | 91 | info->path = info->argv[0]; 92 | if (info->linecount_flag == 1) 93 | { 94 | info->line_count++; 95 | info->linecount_flag = 0; 96 | } 97 | for (i = 0, k = 0; info->arg[i]; i++) 98 | if (!is_delim(info->arg[i], " \t\n")) 99 | k++; 100 | if (!k) 101 | return; 102 | 103 | path = find_path(info, _getenv(info, "PATH="), info->argv[0]); 104 | if (path) 105 | { 106 | info->path = path; 107 | fork_cmd(info); 108 | } 109 | else 110 | { 111 | if ((interactive(info) || _getenv(info, "PATH=") 112 | || info->argv[0][0] == '/') && is_cmd(info, info->argv[0])) 113 | fork_cmd(info); 114 | else if (*(info->arg) != '\n') 115 | { 116 | info->status = 127; 117 | print_error(info, "not found\n"); 118 | } 119 | } 120 | } 121 | 122 | /** 123 | * fork_cmd - forks a an exec thread to run cmd 124 | * @info: the parameter & return info struct 125 | * 126 | * Return: void 127 | */ 128 | void fork_cmd(info_t *info) 129 | { 130 | pid_t child_pid; 131 | 132 | child_pid = fork(); 133 | if (child_pid == -1) 134 | { 135 | /* TODO: PUT ERROR FUNCTION */ 136 | perror("Error:"); 137 | return; 138 | } 139 | if (child_pid == 0) 140 | { 141 | if (execve(info->path, info->argv, get_environ(info)) == -1) 142 | { 143 | free_info(info, 1); 144 | if (errno == EACCES) 145 | exit(126); 146 | exit(1); 147 | } 148 | /* TODO: PUT ERROR FUNCTION */ 149 | } 150 | else 151 | { 152 | wait(&(info->status)); 153 | if (WIFEXITED(info->status)) 154 | { 155 | info->status = WEXITSTATUS(info->status); 156 | if (info->status == 126) 157 | print_error(info, "Permission denied\n"); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /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 | * starts_with - 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 *starts_with(const char *haystack, const char *needle) 51 | { 52 | while (*needle) 53 | if (*needle++ != *haystack++) 54 | return (NULL); 55 | return ((char *)haystack); 56 | } 57 | 58 | /** 59 | * _strcat - concatenates two strings 60 | * @dest: the destination buffer 61 | * @src: the source buffer 62 | * 63 | * Return: pointer to destination buffer 64 | */ 65 | char *_strcat(char *dest, char *src) 66 | { 67 | char *ret = dest; 68 | 69 | while (*dest) 70 | dest++; 71 | while (*src) 72 | *dest++ = *src++; 73 | *dest = *src; 74 | return (ret); 75 | } 76 | -------------------------------------------------------------------------------- /string1.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 | * _strdup - duplicates a string 27 | * @str: the string to duplicate 28 | * 29 | * Return: pointer to the duplicated string 30 | */ 31 | char *_strdup(const char *str) 32 | { 33 | int length = 0; 34 | char *ret; 35 | 36 | if (str == NULL) 37 | return (NULL); 38 | while (*str++) 39 | length++; 40 | ret = malloc(sizeof(char) * (length + 1)); 41 | if (!ret) 42 | return (NULL); 43 | for (length++; length--;) 44 | ret[length] = *--str; 45 | return (ret); 46 | } 47 | 48 | /** 49 | *_puts - prints an input string 50 | *@str: the string to be printed 51 | * 52 | * Return: Nothing 53 | */ 54 | void _puts(char *str) 55 | { 56 | int i = 0; 57 | 58 | if (!str) 59 | return; 60 | while (str[i] != '\0') 61 | { 62 | _putchar(str[i]); 63 | i++; 64 | } 65 | } 66 | 67 | /** 68 | * _putchar - writes the character c to stdout 69 | * @c: The character to print 70 | * 71 | * Return: On success 1. 72 | * On error, -1 is returned, and errno is set appropriately. 73 | */ 74 | int _putchar(char c) 75 | { 76 | static int i; 77 | static char buf[WRITE_BUF_SIZE]; 78 | 79 | if (c == BUF_FLUSH || i >= WRITE_BUF_SIZE) 80 | { 81 | write(1, buf, i); 82 | i = 0; 83 | } 84 | if (c != BUF_FLUSH) 85 | buf[i++] = c; 86 | return (1); 87 | } 88 | -------------------------------------------------------------------------------- /tokenizer.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * **strtow - splits a string into words. Repeat delimiters are ignored 5 | * @str: the input string 6 | * @d: the delimeter string 7 | * Return: a pointer to an array of strings, or NULL on failure 8 | */ 9 | 10 | char **strtow(char *str, char *d) 11 | { 12 | int i, j, k, m, numwords = 0; 13 | char **s; 14 | 15 | if (str == NULL || str[0] == 0) 16 | return (NULL); 17 | if (!d) 18 | d = " "; 19 | for (i = 0; str[i] != '\0'; i++) 20 | if (!is_delim(str[i], d) && (is_delim(str[i + 1], d) || !str[i + 1])) 21 | numwords++; 22 | 23 | if (numwords == 0) 24 | return (NULL); 25 | s = malloc((1 + numwords) * sizeof(char *)); 26 | if (!s) 27 | return (NULL); 28 | for (i = 0, j = 0; j < numwords; j++) 29 | { 30 | while (is_delim(str[i], d)) 31 | i++; 32 | k = 0; 33 | while (!is_delim(str[i + k], d) && str[i + k]) 34 | k++; 35 | s[j] = malloc((k + 1) * sizeof(char)); 36 | if (!s[j]) 37 | { 38 | for (k = 0; k < j; k++) 39 | free(s[k]); 40 | free(s); 41 | return (NULL); 42 | } 43 | for (m = 0; m < k; m++) 44 | s[j][m] = str[i++]; 45 | s[j][m] = 0; 46 | } 47 | s[j] = NULL; 48 | return (s); 49 | } 50 | 51 | /** 52 | * **strtow2 - splits a string into words 53 | * @str: the input string 54 | * @d: the delimeter 55 | * Return: a pointer to an array of strings, or NULL on failure 56 | */ 57 | char **strtow2(char *str, char d) 58 | { 59 | int i, j, k, m, numwords = 0; 60 | char **s; 61 | 62 | if (str == NULL || str[0] == 0) 63 | return (NULL); 64 | for (i = 0; str[i] != '\0'; i++) 65 | if ((str[i] != d && str[i + 1] == d) || 66 | (str[i] != d && !str[i + 1]) || str[i + 1] == d) 67 | numwords++; 68 | if (numwords == 0) 69 | return (NULL); 70 | s = malloc((1 + numwords) * sizeof(char *)); 71 | if (!s) 72 | return (NULL); 73 | for (i = 0, j = 0; j < numwords; j++) 74 | { 75 | while (str[i] == d && str[i] != d) 76 | i++; 77 | k = 0; 78 | while (str[i + k] != d && str[i + k] && str[i + k] != d) 79 | k++; 80 | s[j] = malloc((k + 1) * sizeof(char)); 81 | if (!s[j]) 82 | { 83 | for (k = 0; k < j; k++) 84 | free(s[k]); 85 | free(s); 86 | return (NULL); 87 | } 88 | for (m = 0; m < k; m++) 89 | s[j][m] = str[i++]; 90 | s[j][m] = 0; 91 | } 92 | s[j] = NULL; 93 | return (s); 94 | } 95 | -------------------------------------------------------------------------------- /vars.c: -------------------------------------------------------------------------------- 1 | #include "shell.h" 2 | 3 | /** 4 | * is_chain - test if current char in buffer is a chain delimeter 5 | * @info: the parameter struct 6 | * @buf: the char buffer 7 | * @p: address of current position in buf 8 | * 9 | * Return: 1 if chain delimeter, 0 otherwise 10 | */ 11 | int is_chain(info_t *info, char *buf, size_t *p) 12 | { 13 | size_t j = *p; 14 | 15 | if (buf[j] == '|' && buf[j + 1] == '|') 16 | { 17 | buf[j] = 0; 18 | j++; 19 | info->cmd_buf_type = CMD_OR; 20 | } 21 | else if (buf[j] == '&' && buf[j + 1] == '&') 22 | { 23 | buf[j] = 0; 24 | j++; 25 | info->cmd_buf_type = CMD_AND; 26 | } 27 | else if (buf[j] == ';') /* found end of this command */ 28 | { 29 | buf[j] = 0; /* replace semicolon with null */ 30 | info->cmd_buf_type = CMD_CHAIN; 31 | } 32 | else 33 | return (0); 34 | *p = j; 35 | return (1); 36 | } 37 | 38 | /** 39 | * check_chain - checks we should continue chaining based on last status 40 | * @info: the parameter struct 41 | * @buf: the char buffer 42 | * @p: address of current position in buf 43 | * @i: starting position in buf 44 | * @len: length of buf 45 | * 46 | * Return: Void 47 | */ 48 | void check_chain(info_t *info, char *buf, size_t *p, size_t i, size_t len) 49 | { 50 | size_t j = *p; 51 | 52 | if (info->cmd_buf_type == CMD_AND) 53 | { 54 | if (info->status) 55 | { 56 | buf[i] = 0; 57 | j = len; 58 | } 59 | } 60 | if (info->cmd_buf_type == CMD_OR) 61 | { 62 | if (!info->status) 63 | { 64 | buf[i] = 0; 65 | j = len; 66 | } 67 | } 68 | 69 | *p = j; 70 | } 71 | 72 | /** 73 | * replace_alias - replaces an aliases in the tokenized string 74 | * @info: the parameter struct 75 | * 76 | * Return: 1 if replaced, 0 otherwise 77 | */ 78 | int replace_alias(info_t *info) 79 | { 80 | int i; 81 | list_t *node; 82 | char *p; 83 | 84 | for (i = 0; i < 10; i++) 85 | { 86 | node = node_starts_with(info->alias, info->argv[0], '='); 87 | if (!node) 88 | return (0); 89 | free(info->argv[0]); 90 | p = _strchr(node->str, '='); 91 | if (!p) 92 | return (0); 93 | p = _strdup(p + 1); 94 | if (!p) 95 | return (0); 96 | info->argv[0] = p; 97 | } 98 | return (1); 99 | } 100 | 101 | /** 102 | * replace_vars - replaces vars in the tokenized string 103 | * @info: the parameter struct 104 | * 105 | * Return: 1 if replaced, 0 otherwise 106 | */ 107 | int replace_vars(info_t *info) 108 | { 109 | int i = 0; 110 | list_t *node; 111 | 112 | for (i = 0; info->argv[i]; i++) 113 | { 114 | if (info->argv[i][0] != '$' || !info->argv[i][1]) 115 | continue; 116 | 117 | if (!_strcmp(info->argv[i], "$?")) 118 | { 119 | replace_string(&(info->argv[i]), 120 | _strdup(convert_number(info->status, 10, 0))); 121 | continue; 122 | } 123 | if (!_strcmp(info->argv[i], "$$")) 124 | { 125 | replace_string(&(info->argv[i]), 126 | _strdup(convert_number(getpid(), 10, 0))); 127 | continue; 128 | } 129 | node = node_starts_with(info->env, &info->argv[i][1], '='); 130 | if (node) 131 | { 132 | replace_string(&(info->argv[i]), 133 | _strdup(_strchr(node->str, '=') + 1)); 134 | continue; 135 | } 136 | replace_string(&info->argv[i], _strdup("")); 137 | 138 | } 139 | return (0); 140 | } 141 | 142 | /** 143 | * replace_string - replaces string 144 | * @old: address of old string 145 | * @new: new string 146 | * 147 | * Return: 1 if replaced, 0 otherwise 148 | */ 149 | int replace_string(char **old, char *new) 150 | { 151 | free(*old); 152 | *old = new; 153 | return (1); 154 | } 155 | --------------------------------------------------------------------------------