interpreter.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <assert.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include "reporting.h"
  8. #include "region.h"
  9. #include "stringport.h"
  10. #include "tokenizer.h"
  11. #include "parser.h"
  12. #include "interpreter.h"
  13. #include "builtins.h"
  14. #include "linenoise.h"
  15. int interactive_mode = 0;
  16. void interpret_command(struct AST* n)
  17. {
  18. assert(n->type == NODE_COMMAND);
  19. execvp(n->node.tokens[0], n->node.tokens);
  20. _reporterr("Error: Could not execute the program named [%s]\n", n->node.tokens[0]);
  21. }
  22. void interpret_junction(struct AST* n)
  23. {
  24. pid_t p;
  25. int r;
  26. if (n->type == NODE_COMMAND) {
  27. interpret_command(n);
  28. }
  29. switch(p = fork()) {
  30. case -1:
  31. _reporterr("fork() failure");
  32. break;
  33. case 0:
  34. interpret(n->node.child.l);
  35. break;
  36. default:
  37. waitpid(p, &r, 0);
  38. // DISJ and CONJ are dual
  39. // xor flips the boolean for us depending on the case we're in
  40. //
  41. // so: in a disj (conj) node we exit right away
  42. // if the exit status is (isn't) true
  43. // otherwise continue executing the disj (conj)
  44. // chain.
  45. if ((!WEXITSTATUS(r)) ^ (n->type == NODE_CONJ)) {
  46. _exit(WEXITSTATUS(r));
  47. } else {
  48. interpret(n->node.child.r);
  49. }
  50. break;
  51. }
  52. }
  53. void interpret_pipe(struct AST* n)
  54. {
  55. if (n->type == NODE_COMMAND) {
  56. interpret_command(n);
  57. }
  58. int fd[2];
  59. int f;
  60. pipe(&fd[0]);
  61. f = fork();
  62. if (f == -1) {
  63. _reporterr("fork() failure");
  64. } else if (f == 0) { // child
  65. close(fd[0]);
  66. close(STDOUT_FILENO);
  67. dup(fd[1]);
  68. close(fd[1]);
  69. interpret_command(n->node.child.l);
  70. } else { // parent
  71. close(fd[1]);
  72. close(STDIN_FILENO);
  73. dup(fd[0]);
  74. close(fd[0]);
  75. interpret_pipe(n->node.child.r);
  76. }
  77. }
  78. void interpret(struct AST* n)
  79. {
  80. switch(n->type) {
  81. case NODE_COMMAND:
  82. interpret_command(n);
  83. break;
  84. case NODE_CONJ:
  85. case NODE_DISJ:
  86. interpret_junction(n);
  87. break;
  88. case NODE_PIPE:
  89. interpret_pipe(n);
  90. break;
  91. }
  92. }
  93. void prompt(string_port *port)
  94. {
  95. char *line;
  96. if (interactive_mode) {
  97. if((line = linenoise(geteuid() == 0 ? "s# " : "s$ ")) != NULL) {
  98. *port = (string_port){ .kind=STRPORT_CHAR, .text=line, .place=0 };
  99. }
  100. else {
  101. exit(0);
  102. }
  103. }
  104. }
  105. void loop(FILE *f) {
  106. pid_t p;
  107. int bg;
  108. region r;
  109. struct AST* n;
  110. int status;
  111. string_port port;
  112. if (!interactive_mode) {
  113. port = (string_port){ .kind=STRPORT_FILE, .fptr=f };
  114. }
  115. do {
  116. prompt(&port);
  117. region_create(&r);
  118. n = parse(&r, &port, &bg);
  119. if (n && !perform_builtin(n)) {
  120. if (!(p = fork())) {
  121. interpret(n);
  122. _reporterr("== SHOULD NEVER GET HERE ==");
  123. }
  124. if (!bg) {
  125. waitpid(p, &status, 0);
  126. }
  127. }
  128. region_free(&r);
  129. if (interactive_mode) {
  130. // TODO: Only add if command was sucessful?
  131. linenoiseHistoryAdd(port.text);
  132. free(port.text);
  133. }
  134. else {
  135. skip_newline(&port);
  136. }
  137. } while(!feof(f));
  138. }