Coder Social home page Coder Social logo

minishell's Introduction

minishell

Why does the code look weird ?

The 42 curriculum asks us to code according to the Norme, this standard forbids us certain control structures (like do while, for, ...), a limit of 25 lines and 5 variables per function, 5 function max per .c and and other constraints.

This project has been coded according to the NormeV3 standard.

NormeV3 PDF used in this projetc

Norme repo

Requirements

Clone with submodule

git clone --recurse-submodules [email protected]:fluffy-willa-42-team/minishell.git

or if you have Oh-My-Zsh

gcl [email protected]:fluffy-willa-42-team/minishell.git

You need the GNU readline lib

MacOS

First install Brew

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

For the 42 mac

rm -rf $HOME/.brew && git clone --depth=1 https://github.com/Homebrew/brew $HOME/.brew && echo 'export PATH=$HOME/.brew/bin:$PATH' >> $HOME/.zshrc && source $HOME/.zshrc && brew update

Install GNU readline lib

brew install readline 

Debian/Ubuntu

Install readline lib

 apt install libreadline-dev

Compile

To compile

make

Compile and run

make exe

Compile with fsanitize=address

make SANI=1


This work is published under the terms of 42 Unlicense.

minishell's People

Contributors

fluffy-kaiju avatar willacs avatar

minishell's Issues

Special case for cleaner

TODO FIX

Actual behavior

(o_O)> echo \$PWD
Word
[ ]
[\]
[$]
echo./Users/mahadad/goinfre/minishell...........................

Expected

(o_O)> echo \$PWD
Word
[ ]
[\]
[$]
echo.$PWD.......................................................

Handle empty ENV

Case to test

bash-3.2$ ./a.out $A $A echo UwU
[1]: ->[echo]<-
[2]: ->[UwU]<-

bash-3.2$ ./a.out "$A" "$A" echo UwU
[1]: ->[]<-
[2]: ->[]<-
[3]: ->[echo]<-
[4]: ->[UwU]<-

bash-3.2$ ./a.out '$A' '$A' echo UwU
[1]: ->[$A]<-
[2]: ->[$A]<-
[3]: ->[echo]<-
[4]: ->[UwU]<-

readline return when sigaction call a funtion

readline return if we do two different signal one after another when using sigaction.

UwU $> ^C
UwU $> ^\
   [LOG] readline read

        null line_read
bash-3.2$ 
UwU $> ^\^\^\^\^\^\^\^\^C
[LOG] sigaction call

UwU $> 
   [LOG] readline read

        null line_read

bash-3.2$

Note

readline() is not in the signal-safety list

It's wok with signal() but this function is deprecated.
We need to reset the signal each call.

void sighandler(int signum)
{
(void)signum;
// printf("\nsignum get %d\n", signum);
printf("\n%s", PROMPT_TXT);
signal(SIGINT, sighandler);
signal(SIGQUIT, sighandler);
}
int main(int argc, char *argv[])
{
(void) argc;
(void) argv;
//DEBUG TODO REMOVE
setbuf(stdout, NULL);
signal(SIGINT, sighandler);
signal(SIGQUIT, sighandler);
prompt();
//TODO make custom exit function that free stuff befor quit
return (0);
}

Makefile `DEBUG=2`

Todo

fix the DEBUG=2 flag

Behavior

➜  minishell git:(master) ✗ make DEBUG=2 exe
libft.a :
/!\ DEBUG ENABLE /!\
Flag used:
    -Wall
    -Wextra
    -Werror
vector_lib.a :
/!\ DEBUG ENABLE /!\
Flag used:
    -Wall
    -Wextra
    -Werror
minishell_exe :
/!\ DEBUG ENABLE /!\
Flag used:
    -Wall
    -Wextra
    -Werror

Expected

Add -g3 to the flags compilation.

➜  minishell git:(master) ✗ make DEBUG=2 exe
libft.a :
/!\ DEBUG ENABLE /!\
Flag used:
    -Wall
    -Wextra
    -Werror
    -g3
vector_lib.a :
/!\ DEBUG ENABLE /!\
Flag used:
    -Wall
    -Wextra
    -Werror
    -g3
minishell_exe :
/!\ DEBUG ENABLE /!\
Flag used:
    -Wall
    -Wextra
    -Werror
    -g3

Rework line lexer

  • function array for all pipe case < > << >> |

void line_lexer(t_vec *line, t_vec *instr)
{
size_t i = 0;
int first_elem = 1;
int coun_elem = -1;
g_data.env_path = getenv("PATH");
while (i < line->content_len)
{
if (vec_get_char(line, i) != 0 && ( i == 0 || vec_get_char(line, i - 1) == 0))
{
if (ft_strchr("<>|", vec_get_char(line, i)))
{
printf("[##### PIPE #####]\n");
coun_elem++;
vec_add_instr(instr, coun_elem, 2);
vec_add_char_ptr(get_instr_arg(coun_elem), vec_get_str(line, i));
first_elem = 1;
}
else
{
if (first_elem)
{
printf("[##### CMD #####]\n");
coun_elem++;
// Add the path to the bin in the line buffer.
set_bin_path(line, i);
// Create new instrcution struct in the buffer.
vec_add_instr(instr, coun_elem, 0);//TODO WIP
vec_add_char_ptr(get_instr_arg(coun_elem), vec_get_str(line, i));
first_elem = 0;
}
else
{
printf("[##### ARG #####]\n");
vec_add_char_ptr(get_instr_arg(coun_elem), vec_get_str(line, i));
}
}
printf("[%d]=> [%s]\n", coun_elem, vec_get_str(line, i));
}
i++;
}
print_instr();
}

Console wrap text

Issue

The console wrapping text don't work for the first new line.

Screen.Recording.2022-06-03.at.4.03.36.PM.mov

Todo

  • Try other student repo.
  • Ask on stackoverflow

Line cleaner var substitution deleting one char after it

(o_O)> abc def | xd $PWD hij
[abc def | xd $PWD hij]
Word
[  ]
Word
[  ]
[ |]
[  ]
Word
[  ]
[ $]
[  ]
Word
abc.def.|.xd./Users/fluffy/Code/minishell/willahij..............
abc.def.|.xd./Users/fluffy/Code/minishell/willahij..............


[
    content_len: 3,
    {
        type: 1,
        arg: [
            [0]: "abc",
            [1]: "def",
        ]
    {
        type: 2,
        arg: [
            [0]: "|",
        ]
    {
        type: 1,
        arg: [
            [0]: "xd",
            [1]: "/Users/fluffy/Code/minishell/willahij",
        ]
]

Malloc check

Todo

Check the return from vec_add vec_fill and ...
If one return NULL -> exit failure Malloc fail

Makefile continue de compiler quand une dépendance return une error.

➜  fluffy git:(V3) ✗ make SANI=1 exe
/!\ Debug ➜  vector_lib.a : src/vec_resize.c: In function ‘vec_resize_strict’:
src/vec_resize.c:26:42: error: expected ‘;’ before ‘if’
  printf("########\n#RESIZE#\n########\n")
                                          ^
                                          ;
src/vec_resize.c:28:2:
  if (!vec)
  ~~                                       
make[1]: *** [Makefile:129: vector_lib.a_obj/vec_resize.o] Error 1
/!\ Debug ➜  libft.a : 
/!\ Debug ➜  minishell_exe : 

Possible Leaks in $? implementation

=================================================================
==28351==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 2 byte(s) in 1 object(s) allocated from:
#0 0x7f8dbc12e330 in __interceptor_malloc (/lib/x86_64-linux-gnu/libasan.so.5+0xe9330)
#1 0x5576b5978588 in ft_itoa src/atoi/ft_itoa.c:67
#2 0x5576b5970cab in add_varsub src/1_parser/parser_param_func/lexer_var_sub.c:43
#3 0x5576b5970e61 in varsub src/1_parser/parser_param_func/lexer_var_sub.c:74
#4 0x5576b597089b in line_parser src/1_parser/parser.c:98
#5 0x5576b596fadd in main src/main.c:48
#6 0x7f8dbbc5c09a in __libc_start_main ../csu/libc-start.c:308

SUMMARY: AddressSanitizer: 2 byte(s) leaked in 1 allocation(s).

Valgrind "mem leak"

Todo

Try valgrind on Linux (macos broken)

==61471==
==61471== HEAP SUMMARY:
==61471==     in use at exit: 299,207 bytes in 389 blocks
==61471==   total heap usage: 627 allocs, 238 frees, 322,372 bytes allocated
==61471==
==61471== LEAK SUMMARY:
==61471==    definitely lost: 30,510 bytes in 19 blocks
==61471==    indirectly lost: 134,095 bytes in 190 blocks
==61471==      possibly lost: 2,032 bytes in 1 blocks
==61471==    still reachable: 118,695 bytes in 18 blocks
==61471==         suppressed: 13,875 bytes in 161 blocks
==61471== Rerun with --leak-check=full to see details of leaked memory
==61471==
==61471== Use --track-origins=yes to see where uninitialised values come from
==61471== For lists of detected and suppressed errors, rerun with: -s
==61471== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 1 from 1)

Cleaner need to split args between `|<>`

Actual behavior :

(o_O)> 1|2|3|4|%
1|2|3|4|%.......................................................
CMD [0]=> [WIP/bin/1|2|3|4|%]
[
    {
        type: 0,
        content_len: 1,
        arg: [
            [0]: "WIP/bin/1|2|3|4|%",
        ],
    },
]
(o_O)> 

Expected behavior :

(o_O)> 1|2|3|4|%
1.|.2.|.3.|.4.|.%...............................................
CMD [0]=> [WIP/bin/1]
PIPE [1]=> [|]
CMD [2]=> [WIP/bin/2]
PIPE [3]=> [|]
CMD [4]=> [WIP/bin/3]
PIPE [5]=> [|]
CMD [6]=> [WIP/bin/4]
PIPE [7]=> [|]
CMD [8]=> [WIP/bin/%]
[
    {
        type: 0,
        content_len: 9,
        arg: [
            [0]: "WIP/bin/1",
            [1]: "|",
            [2]: "WIP/bin/2",
            [3]: "|",
            [4]: "WIP/bin/3",
            [5]: "|",
            [6]: "WIP/bin/4",
            [7]: "|",
            [8]: "WIP/bin/%",
        ],
    },
]
(o_O)> 

/**
* Index Conv Function
* ------|------|---------
* [0] | ` ` | whtspc
* [1] | `\t` | whtspc
* [2] | `\n` | whtspc
* [3] | `\v` | whtspc
* [4] | `\f` | whtspc
* [5] | `\r` | whtspc
* [6] | `$` | varsub
* [7] | `\\` | bkslh
*
*/
void line_cleaner(t_vec *vec, char *line)
{
static int (*func_link[10])() = {
whtspc, whtspc, whtspc, whtspc, whtspc, whtspc,
varsub, bkslh, sglqot, dblqot
};
static char *to_find = " \t\n\v\f\r$\\\'\"";
int i;
char *ptr;
i = 0;
while (line[i] && ft_is_whitespace(line[i]))
i++;
while (line[i])
{
ptr = ft_strrchr(to_find, line[i]);
if (ptr)
i = func_link[ptr - to_find](vec, line, i);
else
{
p_vec_add(vec, &line[i]);
i++;
}
}
vec_print(vec);
return ;
}

Linux (Debian) sigaction return `EINVAL`.

Linux (Debian) sigaction return EINVAL.

image

minishell/src/msh_prompt.c

Lines 39 to 101 in 4a9cf26

/**
* @brief Checker for the sigaction return.
*
* @param debug_sigaction `int` that `sigation` return.
* @param name Name of the signal macro.
*/
static void msh_check_sigaction(int sigaction_return, char *name)
{
/**
* sigaction() returns `0` on success; on error, `-1` is returned, and
* `errno` is set to indicate the error.
*/
if (sigaction_return != -1)
{
if (MSH_DEBUG)
printf("%s Ok\n", name);
return ;
}
if (MSH_DEBUG)
printf("%s [KO]: %d !!\n"
"%s\n",
name,
sigaction_return,
strerror(errno)
);
//TODO make a clean exit function, like msh_exit(EXIT_FAILURE, strerror(errno), <...>);
exit(EXIT_FAILURE);
}
/**
* @brief Set sigaction. For `C-c` (SIGINT) will clear the readline buff and
* show up a new prompt. Will ignore `C-\` (SIGQUIT).
*
*/
static void set_sigaction(void)
{
// Settings for the `C-c`
struct sigaction sigint;
struct sigaction sigquit;
sigset_t sig_set;
/**
* Init mask, mask allow to specify a set of signal that aren't permitted
* to iterrupt the handler.
*/
sigemptyset(&sig_set);
sigaddset(&sig_set, SIGINT);
sigaddset(&sig_set, SIGQUIT);
// The function call when the signal is catch.
sigint.sa_handler = sighandler;
// Set the mask
sigint.sa_mask = sig_set;
// Ignore the `c-\` signal.
sigquit.sa_handler = SIG_IGN;
// Set the mask
sigquit.sa_mask = sig_set;
// Start to catch signal.
msh_check_sigaction(sigaction(SIGINT, &sigint, NULL), "SIGINT");
msh_check_sigaction(sigaction(SIGQUIT, &sigquit, NULL), "SIGQUIT");
}

Note

ERRORS
   EFAULT act or oldact points to memory which is not a valid part
          of the process address space.

   EINVAL An invalid signal was specified.  This will also be
          generated if an attempt is made to change the action for
          SIGKILL or SIGSTOP, which cannot be caught or ignored.

GNU implementation of sigaction :

/* Change and/or query the action that will be taken on delivery of
   signal SIG.  If not NULL, ACT describes the new behavior.  If not
   NULL, OACT is set to the prior behavior.  Return 0 on success, or
   set errno and return -1 on failure.  */
int
sigaction (int sig, const struct sigaction *restrict act,
           struct sigaction *restrict oact)
{
  sigset_t mask;
  sigset_t oldmask;
  int saved_errno;

  if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP
      || (act && act->sa_handler == SIG_ERR))
    {
      errno = EINVAL;
      return -1;
    }

https://github.com/coreutils/gnulib/blob/9cde39f881204e422d4bdad67ab12877d6a8172d/lib/sigaction.c#L126-L143

  if (act)
    {
      /* Safe to install the handler before updating action_array,
         since all signals are currently blocked.  */
      if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN)
        {
          if (signal (sig, act->sa_handler) == SIG_ERR)
            goto failure;
          action_array[sig].sa_handler = NULL;
        }
      else
        {
          if (signal (sig, sigaction_handler) == SIG_ERR)
            goto failure;
          action_array[sig] = *act;
        }
    }
  sigprocmask (SIG_SETMASK, &oldmask, NULL);
  return 0;

 failure:
  saved_errno = errno;
  sigprocmask (SIG_SETMASK, &oldmask, NULL);
  errno = saved_errno;
  return -1;

https://github.com/coreutils/gnulib/blob/9cde39f881204e422d4bdad67ab12877d6a8172d/lib/sigaction.c#L179-L203

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.