parser.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * File: parser.c
  3. * Author: Arthur Brandao
  4. *
  5. * Created on 31 octobre 2018
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include <errno.h>
  11. #include "parser.h"
  12. /* --- Fonctions privées --- */
  13. int nb_commands(char* line){
  14. //Initialisation variable
  15. int compteur = 0;
  16. //Parcours chaine pour chercher séparateur et compter le nombre de commande
  17. while(*line){
  18. //Si un ;
  19. if(*line == ';'){
  20. compteur++;
  21. }
  22. //Si | ou ||
  23. else if(*line == '|'){
  24. //Verif que ce n'est pas le dernier carac
  25. if(*(line + 1) == '\0'){
  26. return SHELL_ERR;
  27. }
  28. //Si un || on avance de 1 en plus
  29. else if(*(line + 1) == '|'){
  30. //Si à la fin de la chaine
  31. if(*(line + 2) == '\0'){
  32. return SHELL_ERR;
  33. }
  34. line++;
  35. }
  36. compteur++;
  37. }
  38. //Si un &&
  39. if(*line == '&'){
  40. //Si celui d'apres est bien un &&
  41. if(*(line + 1) == '&'){
  42. line++;
  43. compteur++;
  44. }
  45. //Sinon il doit y avoir un vide pour etre le & du bck ou un > avant
  46. else if(*(line + 1) != '\0' && *(line - 1) != '>'){
  47. return SHELL_ERR;
  48. }
  49. }
  50. line++;
  51. }
  52. //Ajoute la dernière commande
  53. compteur++;
  54. return compteur;
  55. }
  56. /**
  57. * Recup la 1er commande
  58. * @param c Structure commande à initialiser
  59. * @param line Ligne avec la commande
  60. * @return int Le décallage à effectuer dans line
  61. */
  62. int get_command(Command* c, char* line){
  63. //Declaration variable
  64. char* deb = line, * old;
  65. int length = 0, separator = 0, next = SHELL_NONE;
  66. //Parcours chaine pour chercher un séparateur
  67. while(*line){
  68. //Si un ;
  69. if(*line == ';'){
  70. separator = 1;
  71. break;
  72. }
  73. //Si | ou ||
  74. else if(*line == '|'){
  75. //Si 1 ou 2 |
  76. if(*(line + 1) == '|'){
  77. separator = 2;
  78. next = SHELL_ELSE;
  79. } else {
  80. separator = 1;
  81. next = SHELL_PIPE;
  82. }
  83. break;
  84. }
  85. //Si un &&
  86. if(*line == '&'){
  87. //Si celui d'apres est bien un &&
  88. if(*(line + 1) == '&'){
  89. separator = 2;
  90. next = SHELL_IF;
  91. break;
  92. }
  93. }
  94. length++;
  95. line++;
  96. }
  97. //Verif si c'est la dernière commande
  98. if(!*line){
  99. next = SHELL_END;
  100. }
  101. //Allocation memoire et copie chaine
  102. c->cmd = malloc(sizeof(char) * (length + 1));
  103. strncpy(c->cmd, deb, length);
  104. c->next = next;
  105. c->argc = 0;
  106. c->input = STDIN;
  107. c->output = STDOUT;
  108. c->error = STDERR;
  109. //Trim et supprime l'ancienne chaine
  110. old = c->cmd;
  111. c->cmd = rtrim(c->cmd, ' ');
  112. free(old);
  113. //Retour
  114. return length + separator;
  115. }
  116. /* --- Fonctions publiques --- */
  117. int parse_line(CommandTab* ct, char* line){
  118. //Declaration variable
  119. int compteur, tmp;
  120. //Nettoyage ligne
  121. line = trim(mtrim(line, '\n'));
  122. //Compte le nombre de commande dans la ligne
  123. compteur = nb_commands(line);
  124. if(compteur == SHELL_ERR){
  125. return SHELL_ERR;
  126. }
  127. //Initialisation structure
  128. ct->cmd = malloc(sizeof(Command*) * compteur);
  129. ct->length = compteur;
  130. //Recupération de chaque commande
  131. for(int i = 0; i < compteur; i++){
  132. ct->cmd[i] = malloc(sizeof(Command));
  133. tmp = get_command(ct->cmd[i], line);
  134. line += tmp;
  135. //Si pas dernière commande on trim
  136. if(i + 1 < compteur){
  137. line = ltrim(line, ' ');
  138. }
  139. }
  140. //Retour
  141. return SHELL_OK;
  142. }
  143. int parse_command(Command* c){
  144. boolean guillemet = false;
  145. char* deb, * file, * buffer = c->cmd + 1;
  146. int redir = 0, compteur;
  147. //Parcours chaine
  148. while(*buffer){
  149. //Repere redirection
  150. while(*buffer){
  151. //Entrée
  152. if(*buffer == '<'){
  153. //Si il n'y a rien apres
  154. if(!(*(buffer + 1))){
  155. return SHELL_ERR;
  156. }
  157. buffer++;
  158. redir = SHELLR_IN;
  159. break;
  160. }
  161. //Sortie
  162. else if (*buffer == '>'){
  163. //Si il n'y a rien apres
  164. if(!(*(buffer + 1))){
  165. return SHELL_ERR;
  166. } else {
  167. buffer++;
  168. //Si >>
  169. if(*buffer == '>'){
  170. //Si il n'y a rien apres
  171. if(!(*(buffer + 1))){
  172. return SHELL_ERR;
  173. } else {
  174. buffer++;
  175. //Si >>&
  176. if(*buffer == '&'){
  177. //Si il n'y a rien apres
  178. if(!(*(buffer + 1))){
  179. return SHELL_ERR;
  180. }
  181. buffer++;
  182. redir = SHELLRE_ALL;
  183. }
  184. //Sinon toujours >>
  185. else {
  186. redir = SHELLR_OUT;
  187. }
  188. }
  189. }
  190. // Si >&
  191. else if(*buffer == '&'){
  192. //Si il n'y a rien apres
  193. if(!(*(buffer + 1))){
  194. return SHELL_ERR;
  195. }
  196. redir = SHELLRE_ALL;
  197. buffer++;
  198. }
  199. //Sinon >
  200. else {
  201. redir = SHELLRE_OUT;
  202. }
  203. }
  204. break;
  205. }
  206. //Sortie erreur
  207. else if (*buffer == '2' && *(buffer - 1) == ' ' && *(buffer + 1) && *(buffer + 1) == '>'){
  208. buffer++;
  209. //Si il n'y a rien apres
  210. if(!(*(buffer + 1))){
  211. return SHELL_ERR;
  212. } else {
  213. buffer++;
  214. //Si 2>>
  215. if(*buffer == '>'){
  216. buffer++;
  217. //Si il n'y a rien apres
  218. if(!(*(buffer + 1))){
  219. return SHELL_ERR;
  220. }
  221. redir = SHELLR_ERR;
  222. }
  223. //Sinon 2>
  224. else {
  225. redir = SHELLRE_ERR;
  226. }
  227. }
  228. break;
  229. }
  230. buffer++;
  231. }
  232. //On passe les espaces
  233. while(*buffer == ' '){
  234. buffer++;
  235. }
  236. //Si on est à la fin de la chaine
  237. if(*buffer == '\0'){
  238. return SHELL_ERR;
  239. }
  240. //Regarde si le nom du fichier est entre ""
  241. guillemet = *buffer == '"';
  242. //Sauvegarde debut nom fichier
  243. deb = buffer;
  244. compteur = 0;
  245. //Lecture nom du fichier
  246. while(*buffer){
  247. //Incremente
  248. compteur++;
  249. buffer++;
  250. //Test arret
  251. if(guillemet && *buffer == '"'){
  252. break;
  253. }
  254. else if(!guillemet && (*buffer == '<' || *buffer == '>' || (*buffer == ' ' && *(buffer - 1) != '\\'))){
  255. break;
  256. }
  257. }
  258. //Si fin de la commande et guillemet alors erreur
  259. if(!(*buffer) && guillemet){
  260. return SHELL_ERR;
  261. }
  262. //Retire guillement si besoin
  263. if(guillemet){
  264. deb++;
  265. compteur--;
  266. buffer++;
  267. }
  268. //Allocation file et copie nom fichier
  269. file = malloc(sizeof(char) * compteur);
  270. strncpy(file, deb, compteur);
  271. printf("%s %d %d\n", file, redir, guillemet);
  272. free(file);
  273. //Passe les espaces
  274. while(*buffer == ' '){
  275. buffer++;
  276. }
  277. }
  278. return 1;
  279. }
  280. int parse_all_command(CommandTab* ct){
  281. int tmp;
  282. for(int i = 0; i < ct->length; i++){
  283. tmp = parse_command(ct->cmd[i]);
  284. if(tmp != SHELL_OK){
  285. return SHELL_FAIL;
  286. }
  287. }
  288. return SHELL_OK;
  289. }
  290. void clean_command(CommandTab* ct){
  291. extern int errno;
  292. //Vide le tableau
  293. for(int i = 0; i < ct->length; i++){
  294. //Si la commande a été parsée on vide les arguments
  295. if(ct->cmd[i]->argc > 0){
  296. ct->cmd[i]->name = NULL;
  297. for(int j = 0; j < ct->cmd[i]->argc; j++){
  298. free(ct->cmd[i]->argv[j]);
  299. }
  300. }
  301. //Ferme les fichiers ouverts si besoin
  302. if(ct->cmd[i]->input != STDIN){
  303. if(close(ct->cmd[i]->input)){
  304. fprintf(stderr, "Erreur lors de la fermeture du fichier d'input de %s : %s", ct->cmd[i]->cmd, strerror(errno));
  305. }
  306. }
  307. if(ct->cmd[i]->output != STDOUT){
  308. if(close(ct->cmd[i]->output)){
  309. fprintf(stderr, "Erreur lors de la fermeture du fichier d'output de %s : %s", ct->cmd[i]->cmd, strerror(errno));
  310. }
  311. }
  312. if(ct->cmd[i]->error != STDERR){
  313. if(close(ct->cmd[i]->error)){
  314. fprintf(stderr, "Erreur lors de la fermeture du fichier d'error de %s : %s", ct->cmd[i]->cmd, strerror(errno));
  315. }
  316. }
  317. //Supprime la ligne de commande
  318. free(ct->cmd[i]->cmd);
  319. //Supprime la structure
  320. free(ct->cmd[i]);
  321. }
  322. //Met à 0 la taille du tableau
  323. ct->length = 0;
  324. }