mirror of
https://github.com/Savapitech/42sh.git
synced 2026-01-18 16:57:28 +01:00
Add basic readline
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
|
[reports]
|
||||||
|
merge = "multiplier"
|
||||||
|
|||||||
132
src/readline.c
Normal file
132
src/readline.c
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
** EPITECH PROJECT, 2025
|
||||||
|
** __
|
||||||
|
** File description:
|
||||||
|
** _
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "readline.h"
|
||||||
|
#include "u_str.h"
|
||||||
|
|
||||||
|
static
|
||||||
|
size_t strcpy_printable(char *dest, char const *src, size_t n)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
if (isprint(src[i])) {
|
||||||
|
*dest = src[i];
|
||||||
|
count++;
|
||||||
|
dest++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool str_printable(char const *str, size_t size)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < size; i++)
|
||||||
|
if (!isprint(str[i]))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool ensure_buff_av_capacity(buff_t *buff, size_t requested)
|
||||||
|
{
|
||||||
|
char *new_str;
|
||||||
|
size_t endsize = BUFF_INIT_SZ;
|
||||||
|
|
||||||
|
if ((buff->sz + requested) < buff->cap)
|
||||||
|
return true;
|
||||||
|
for (; endsize < buff->sz + requested; endsize <<= 1);
|
||||||
|
if (endsize > buff->cap) {
|
||||||
|
new_str = realloc(buff->str, (sizeof *buff->str) * endsize);
|
||||||
|
if (new_str == NULL)
|
||||||
|
return false;
|
||||||
|
buff->str = new_str;
|
||||||
|
buff->cap = endsize;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool ensure_buff_capacity(buff_t *buff)
|
||||||
|
{
|
||||||
|
char *new_str;
|
||||||
|
|
||||||
|
if (buff->str == NULL) {
|
||||||
|
new_str = malloc((sizeof *buff->str) * BUFF_INIT_SZ);
|
||||||
|
if (new_str == NULL)
|
||||||
|
return false;
|
||||||
|
buff->str = new_str;
|
||||||
|
buff->cap = BUFF_INIT_SZ;
|
||||||
|
}
|
||||||
|
if (buff->sz == buff->cap) {
|
||||||
|
new_str = realloc(buff->str, (sizeof *buff->str) * buff->cap << 1);
|
||||||
|
if (new_str == NULL)
|
||||||
|
return false;
|
||||||
|
buff->str = new_str;
|
||||||
|
buff->cap <<= 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool append_null_terminator(buff_t *buff)
|
||||||
|
{
|
||||||
|
if (!ensure_buff_av_capacity(buff, 1))
|
||||||
|
return false;
|
||||||
|
buff->str[buff->sz] = '\0';
|
||||||
|
buff->sz++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int8_t handle_line_buff(buff_t *buff, char *read_buff, ssize_t read_size)
|
||||||
|
{
|
||||||
|
if (*read_buff == CTRL('d')) {
|
||||||
|
buff->sz = 0;
|
||||||
|
return WRITE_CONST(STDOUT_FILENO, "exit\n"), RETURN_SUCCESS;
|
||||||
|
}
|
||||||
|
if (str_printable(read_buff, read_size))
|
||||||
|
write(STDOUT_FILENO, read_buff, read_size);
|
||||||
|
if (!ensure_buff_av_capacity(buff, read_size))
|
||||||
|
return RETURN_FAILURE;
|
||||||
|
buff->sz += strcpy_printable(buff->str + buff->sz,
|
||||||
|
read_buff, read_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readline(buff_t *buff)
|
||||||
|
{
|
||||||
|
char read_buff[32] = "";
|
||||||
|
ssize_t read_size = 0;
|
||||||
|
|
||||||
|
if (!ensure_buff_capacity(buff))
|
||||||
|
return false;
|
||||||
|
while (*read_buff != '\n' && *read_buff != '\r') {
|
||||||
|
memset(read_buff, '\0', sizeof read_buff);
|
||||||
|
read_size = read(STDIN_FILENO, &read_buff, sizeof read_buff - 1);
|
||||||
|
if (read_size < 0)
|
||||||
|
return false;
|
||||||
|
if (read_size == 0) {
|
||||||
|
buff->sz = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (handle_line_buff(buff, read_buff, read_size) > -1)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
U_DEBUG("buff count: %zu\n", buff->sz);
|
||||||
|
return append_null_terminator(buff);
|
||||||
|
}
|
||||||
17
src/readline.h
Normal file
17
src/readline.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
** EPITECH PROJECT, 2025
|
||||||
|
** __
|
||||||
|
** File description:
|
||||||
|
** _
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef READLINE
|
||||||
|
#define READLINE
|
||||||
|
#define CTRL(x) (x & 0xf)
|
||||||
|
#define BUFF_INIT_SZ 128
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "u_str.h"
|
||||||
|
|
||||||
|
bool readline(buff_t *buff);
|
||||||
|
#endif /* READLINE */
|
||||||
22
src/shell.c
22
src/shell.c
@@ -16,6 +16,7 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "env.h"
|
#include "env.h"
|
||||||
#include "history.h"
|
#include "history.h"
|
||||||
|
#include "readline.h"
|
||||||
#include "shell.h"
|
#include "shell.h"
|
||||||
#include "u_str.h"
|
#include "u_str.h"
|
||||||
|
|
||||||
@@ -56,22 +57,20 @@ void write_prompt(int is_a_tty)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
bool change_shell_command(char **buffer, exec_ctx_t *exec_ctx,
|
bool change_shell_command(buff_t *buff, exec_ctx_t *exec_ctx)
|
||||||
size_t buffer_sz)
|
|
||||||
{
|
{
|
||||||
size_t buffer_len = 0;
|
|
||||||
char *tmp_buff = NULL;
|
char *tmp_buff = NULL;
|
||||||
|
|
||||||
if (getline(buffer, &buffer_sz, stdin) == -1)
|
if (!readline(buff))
|
||||||
return true;
|
return true;
|
||||||
tmp_buff = (*buffer);
|
tmp_buff = buff->str;
|
||||||
buffer_len = update_command(&tmp_buff, &buffer_sz, exec_ctx);
|
buff->sz = update_command(&tmp_buff, &buff->sz, exec_ctx);
|
||||||
if (buffer_len < 1 || !u_str_is_alnum(tmp_buff)) {
|
if (buff->sz < 1 || !u_str_is_alnum(tmp_buff)) {
|
||||||
check_basic_error(tmp_buff);
|
check_basic_error(tmp_buff);
|
||||||
free(tmp_buff);
|
free(tmp_buff);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
U_DEBUG("Buffer [%lu] [%s]\n", buffer_len, buffer);
|
U_DEBUG("Buffer [%lu] [%s]\n", buff->sz, buff->str);
|
||||||
visitor(tmp_buff, exec_ctx);
|
visitor(tmp_buff, exec_ctx);
|
||||||
free(tmp_buff);
|
free(tmp_buff);
|
||||||
return false;
|
return false;
|
||||||
@@ -80,16 +79,15 @@ bool change_shell_command(char **buffer, exec_ctx_t *exec_ctx,
|
|||||||
static
|
static
|
||||||
int shell_loop(int is_a_tty, exec_ctx_t *exec_ctx)
|
int shell_loop(int is_a_tty, exec_ctx_t *exec_ctx)
|
||||||
{
|
{
|
||||||
char *buffer = NULL;
|
buff_t buff = { .str = NULL, 0 };
|
||||||
size_t buffer_sz = 0;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
write_prompt(is_a_tty);
|
write_prompt(is_a_tty);
|
||||||
if (change_shell_command(&buffer, exec_ctx, buffer_sz) == true)
|
if (change_shell_command(&buff, exec_ctx))
|
||||||
return exec_ctx->history->last_exit_code;
|
return exec_ctx->history->last_exit_code;
|
||||||
}
|
}
|
||||||
free(exec_ctx->history_command);
|
free(exec_ctx->history_command);
|
||||||
return (free(buffer), exec_ctx->history->last_exit_code);
|
return free(buff.str), exec_ctx->history->last_exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
his_command_t *init_cmd_history(void)
|
his_command_t *init_cmd_history(void)
|
||||||
|
|||||||
Reference in New Issue
Block a user