parser.c 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. /*
  3. * Copyright (C) 2022, 2023 Ferass El Hafidi <vitali64pmemail@protonmail.com>
  4. */
  5. #define _POSIX_C_SOURCE 200809L
  6. /* POSIX Header Files */
  7. #include <unistd.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <errno.h>
  12. #include <signal.h>
  13. #include <sys/wait.h>
  14. /* sh Header Files */
  15. #include "parser.h"
  16. #include "commands.h"
  17. int parseCommand(int, char **);
  18. int splitCommand(char [4096], char *[4096]);
  19. /* Parse a shell command and determine if the command to run is built-in or
  20. * external. It then runs the command accordinately.
  21. * <It also could in the future handle tokens.>
  22. */
  23. int parseCommand(int argc, char *argv[]) {
  24. struct sigaction signal_action;
  25. int status_code = 0, err = 0;
  26. pid_t isparent;
  27. if (argc == 0) return 0; /* There's no argument. */
  28. if (!strcmp(argv[0], "cd")) return builtin_cd(argc, argv);
  29. /* The command isn't built-in. */
  30. isparent = fork();
  31. wait(&status_code);
  32. if (!isparent) {
  33. /* Do not ignore SIGINT when in a child process. */
  34. signal_action.sa_handler = SIG_DFL;
  35. sigemptyset(&signal_action.sa_mask);
  36. sigaction(SIGINT, &signal_action, NULL);
  37. /* Some sh implementations manually search for the command in PATH.
  38. * This is not needed here because execvp is going to search for
  39. * that command in PATH anyway.
  40. */
  41. status_code = execvp(argv[0], argv);
  42. /* If the child process is still alive, we know execvp(3) failed. */
  43. exit(-errno);
  44. }
  45. /* This code may be used to store the exit value in $?. */
  46. //if (errno != EINTR && WEXITSTATUS(status_code) !=) return WEXITSTATUS(status_code);
  47. //else return 0;
  48. err = WEXITSTATUS(status_code);
  49. if (err-256 == -E2BIG || err-256 == -EACCES || err-256 == -EINVAL ||
  50. err-256 == -ELOOP ||
  51. err-256 == -ENAMETOOLONG || err-256 == -ENOENT || err-256 == -ENOTDIR)
  52. printf("sh: %s: %s\n", argv[0], strerror(-(err-256)));
  53. return err;
  54. }
  55. /* This splits a command string in multiple words.
  56. * The array command can then be ran using execvp(3). It
  57. * also returns an int that can be used as argc.
  58. */
  59. int splitCommand(char name[4096], char *splitted_name[4096]) {
  60. long unsigned int array_index = 1;
  61. char *token;
  62. if ((token = strtok(name, " ")) != NULL && token[0] != '#')
  63. splitted_name[0] = token;
  64. else return 0;
  65. /* WARNING: Not thread-safe! */
  66. for (; (token = strtok(NULL, " ")) != NULL &&
  67. token[0] != '#' &&
  68. (splitted_name[array_index] = token); array_index++)
  69. /* Do nothing. */ ;
  70. return array_index;
  71. }