parser.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  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 <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <fcntl.h>
  14. #include "wildcard.h"
  15. #include "parser.h"
  16. /* --- Fonctions privées --- */
  17. int nb_commands(char* line){
  18. //Initialisation variable
  19. int compteur = 0;
  20. //Parcours chaine pour chercher séparateur et compter le nombre de commande
  21. while(*line){
  22. //Si un ;
  23. if(*line == ';'){
  24. compteur++;
  25. }
  26. //Si | ou ||
  27. else if(*line == '|'){
  28. //Verif que ce n'est pas le dernier carac
  29. if(*(line + 1) == '\0'){
  30. return SHELL_ERR;
  31. }
  32. //Si un || on avance de 1 en plus
  33. else if(*(line + 1) == '|'){
  34. //Si à la fin de la chaine
  35. if(*(line + 2) == '\0'){
  36. return SHELL_ERR;
  37. }
  38. line++;
  39. }
  40. compteur++;
  41. }
  42. //Si un &&
  43. if(*line == '&'){
  44. //Si celui d'apres est bien un &&
  45. if(*(line + 1) == '&'){
  46. line++;
  47. compteur++;
  48. }
  49. //Sinon il doit y avoir un vide pour etre le & du bck ou un > avant
  50. else if(*(line + 1) != '\0' && *(line - 1) != '>'){
  51. return SHELL_ERR;
  52. }
  53. }
  54. line++;
  55. }
  56. //Ajoute la dernière commande
  57. compteur++;
  58. return compteur;
  59. }
  60. /**
  61. * Recup la 1er commande
  62. * @param c Structure commande à initialiser
  63. * @param line Ligne avec la commande
  64. * @return int Le décallage à effectuer dans line
  65. */
  66. int get_command(Command* c, char* line){
  67. //Declaration variable
  68. char* deb = line;
  69. int length = 0, separator = 0, next = SHELL_NONE;
  70. //Parcours chaine pour chercher un séparateur
  71. while(*line){
  72. //Si un ;
  73. if(*line == ';'){
  74. separator = 1;
  75. break;
  76. }
  77. //Si | ou ||
  78. else if(*line == '|'){
  79. //Si 1 ou 2 |
  80. if(*(line + 1) == '|'){
  81. separator = 2;
  82. next = SHELL_ELSE;
  83. } else {
  84. separator = 1;
  85. next = SHELL_PIPE;
  86. }
  87. break;
  88. }
  89. //Si un &&
  90. if(*line == '&'){
  91. //Si celui d'apres est bien un &&
  92. if(*(line + 1) == '&'){
  93. separator = 2;
  94. next = SHELL_IF;
  95. break;
  96. }
  97. }
  98. length++;
  99. line++;
  100. }
  101. //Verif si c'est la dernière commande
  102. if(!*line){
  103. next = SHELL_END;
  104. }
  105. //Allocation memoire et copie chaine
  106. c->cmd = malloc(sizeof(char) * (length + 1));
  107. memset(c->cmd, 0, length + 1);
  108. strncpy(c->cmd, deb, length);
  109. c->next = next;
  110. c->argc = 0;
  111. c->input = STDIN;
  112. c->output = STDOUT;
  113. c->error = STDERR;
  114. c->erase[0] = false;
  115. c->erase[1] = false;
  116. //Retour
  117. return length + separator;
  118. }
  119. int set_io(Command* c, char* filename, int redir){
  120. //Declaration variable
  121. int file;
  122. //Ouverture du fichier
  123. file = open(filename, O_CREAT | O_RDWR, S_IRWXU);
  124. if(file == ERR){
  125. perror("Erreur lors de l'ouverture du fichier pour la redirection : ");
  126. return SHELL_ERR;
  127. }
  128. //Analyse dans quel descripteur il doit etre mis
  129. switch(redir){
  130. case SHELLR_IN:
  131. //Si un fichier deja ouvert
  132. if(c->input != STDIN){
  133. //On le ferme
  134. if(close(c->input) == -1){
  135. perror("Erreur lors de la fermeture de l'ancien fichier de redirection : ");
  136. }
  137. }
  138. //Set nouveau fichier
  139. c->input = file;
  140. break;
  141. case SHELLR_OUT:
  142. case SHELLRE_OUT:
  143. //Si un fichier deja ouvert
  144. if(c->output != STDOUT){
  145. //On le ferme
  146. if(close(c->output) == -1){
  147. perror("Erreur lors de la fermeture de l'ancien fichier de redirection : ");
  148. }
  149. }
  150. c->output = file;
  151. if(redir == SHELLRE_OUT){
  152. c->erase[STDOUT - 1] = true;
  153. }
  154. break;
  155. case SHELLR_ERR:
  156. case SHELLRE_ERR:
  157. //Si un fichier deja ouvert
  158. if(c->error != STDERR){
  159. //On le ferme
  160. if(close(c->error) == -1){
  161. perror("Erreur lors de la fermeture de l'ancien fichier de redirection : ");
  162. }
  163. }
  164. c->error = file;
  165. if(redir == SHELLRE_ERR){
  166. c->erase[STDERR - 1] = true;
  167. }
  168. break;
  169. case SHELLR_ALL:
  170. case SHELLRE_ALL:
  171. //Si un fichier deja ouvert
  172. if(c->output != STDOUT){
  173. //On le ferme
  174. if(close(c->output) == -1){
  175. perror("Erreur lors de la fermeture de l'ancien fichier de redirection : ");
  176. }
  177. }
  178. if(c->error != STDERR){
  179. //On le ferme
  180. if(close(c->error) == -1){
  181. perror("Erreur lors de la fermeture de l'ancien fichier de redirection : ");
  182. }
  183. }
  184. c->output = file;
  185. c->error = file;
  186. if(redir == SHELLRE_ALL){
  187. c->erase[STDOUT - 1] = true;
  188. c->erase[STDERR - 1] = true;
  189. }
  190. break;
  191. default :
  192. return SHELL_ERR;
  193. }
  194. //Si on arrive ici tous est ok
  195. return SHELL_OK;
  196. }
  197. int set_redirection(Command* c){
  198. boolean first = true, guillemet = false;
  199. char* deb, * file, * buffer = c->cmd + 1;
  200. int redir = -1, compteur, finCmd = 0;
  201. //Parcours chaine
  202. while(*buffer){
  203. //Repere redirection
  204. while(*buffer){
  205. //Entrée
  206. if(*buffer == '<'){
  207. //Si il n'y a rien apres
  208. if(!(*(buffer + 1))){
  209. return SHELL_ERR;
  210. }
  211. buffer++;
  212. redir = SHELLR_IN;
  213. break;
  214. }
  215. //Sortie
  216. else if (*buffer == '>'){
  217. //Si il n'y a rien apres
  218. if(!(*(buffer + 1))){
  219. return SHELL_ERR;
  220. } else {
  221. buffer++;
  222. //Si >>
  223. if(*buffer == '>'){
  224. //Si il n'y a rien apres
  225. if(!(*(buffer + 1))){
  226. return SHELL_ERR;
  227. } else {
  228. buffer++;
  229. //Si >>&
  230. if(*buffer == '&'){
  231. //Si il n'y a rien apres
  232. if(!(*(buffer + 1))){
  233. return SHELL_ERR;
  234. }
  235. buffer++;
  236. redir = SHELLRE_ALL;
  237. }
  238. //Sinon toujours >>
  239. else {
  240. redir = SHELLR_OUT;
  241. }
  242. }
  243. }
  244. // Si >&
  245. else if(*buffer == '&'){
  246. //Si il n'y a rien apres
  247. if(!(*(buffer + 1))){
  248. return SHELL_ERR;
  249. }
  250. redir = SHELLRE_ALL;
  251. buffer++;
  252. }
  253. //Sinon >
  254. else {
  255. redir = SHELLRE_OUT;
  256. }
  257. }
  258. break;
  259. }
  260. //Sortie erreur
  261. else if (*buffer == '2' && *(buffer - 1) == ' ' && *(buffer + 1) && *(buffer + 1) == '>'){
  262. buffer++;
  263. //Si il n'y a rien apres
  264. if(!(*(buffer + 1))){
  265. return SHELL_ERR;
  266. } else {
  267. buffer++;
  268. //Si 2>>
  269. if(*buffer == '>'){
  270. buffer++;
  271. //Si il n'y a rien apres
  272. if(!(*(buffer + 1))){
  273. return SHELL_ERR;
  274. }
  275. redir = SHELLR_ERR;
  276. }
  277. //Sinon 2>
  278. else {
  279. redir = SHELLRE_ERR;
  280. }
  281. }
  282. break;
  283. }
  284. buffer++;
  285. //On incremente pour trouver la fin de la commande
  286. if(first){
  287. finCmd++;
  288. }
  289. }
  290. //Apres ce n'est que des redirection
  291. first = false;
  292. //On passe les espaces
  293. while(*buffer == ' '){
  294. buffer++;
  295. }
  296. //Si on est à la fin de la chaine
  297. if(*buffer == '\0'){
  298. if(redir == -1){
  299. //Aucune redirection
  300. return finCmd + 1;
  301. }
  302. //Sinon on est dans un redirection non terminée
  303. return SHELL_ERR;
  304. }
  305. //Regarde si le nom du fichier est entre ""
  306. guillemet = *buffer == '"';
  307. //Sauvegarde debut nom fichier
  308. deb = buffer;
  309. compteur = 0;
  310. //Lecture nom du fichier
  311. while(*buffer){
  312. //Incremente
  313. compteur++;
  314. buffer++;
  315. //Test arret
  316. if(guillemet && *buffer == '"'){
  317. break;
  318. }
  319. else if(!guillemet && (*buffer == '<' || *buffer == '>' || (*buffer == ' ' && *(buffer - 1) != '\\'))){
  320. break;
  321. }
  322. }
  323. //Si fin de la commande et guillemet alors erreur
  324. if(!(*buffer) && guillemet){
  325. return SHELL_ERR;
  326. }
  327. //Retire guillement si besoin
  328. if(guillemet){
  329. deb++;
  330. compteur--;
  331. buffer++;
  332. }
  333. //Allocation file et copie nom fichier
  334. file = malloc(sizeof(char) * compteur);
  335. memset(file, 0, compteur);
  336. strncpy(file, deb, compteur);
  337. //Redirection
  338. if(set_io(c, file, redir) == SHELL_ERR){
  339. free(file);
  340. return SHELL_ERR;
  341. }
  342. free(file);
  343. //Passe les espaces
  344. while(*buffer == ' '){
  345. buffer++;
  346. }
  347. }
  348. //Si on arrive ici tous est ok
  349. return finCmd + 1;
  350. }
  351. int split_command(Command* c, char* cmd){
  352. //Declaration variable
  353. char* deb = cmd;
  354. int nb = 0, length = 0, i = 0;
  355. char delim = ' ';
  356. boolean chercheFin = false;
  357. //Compte le nombre d'argument
  358. while(*cmd != '\0' && *cmd != '&'){
  359. //Cherche debut d'un mot
  360. if(*cmd != ' ' && !chercheFin){
  361. chercheFin = true;
  362. //Guillemet
  363. if(*cmd == '"'){
  364. //Verif que ce n'est pas la fin
  365. if(!(*(cmd + 1))){
  366. return SHELL_ERR;
  367. }
  368. cmd++;
  369. delim = '"';
  370. }
  371. //Mot sans guillemet autour
  372. else {
  373. length = 0;
  374. delim = ' ';
  375. }
  376. }
  377. //Fin d'un mot
  378. else if(*cmd == delim && chercheFin){
  379. //Adapte si il y avait des guillemet
  380. chercheFin = false;
  381. nb++;
  382. }
  383. //Incremente
  384. cmd++;
  385. }
  386. //Si on termine sur un mot sans "
  387. if(chercheFin){
  388. nb++;
  389. }
  390. //Allocation + retour au debut
  391. c->argv = malloc(sizeof(char*) * (nb + 1));
  392. c->argc = nb;
  393. cmd = deb;
  394. //Parcours chaine et decoupe
  395. while(*cmd != '\0' && *cmd != '&'){
  396. //Cherche debut d'un mot
  397. if(*cmd != ' ' && !chercheFin){
  398. chercheFin = true;
  399. //Guillemet
  400. if(*cmd == '"'){
  401. cmd++;
  402. deb = cmd;
  403. length = 0;
  404. delim = '"';
  405. }
  406. //Mot sans guillemet autour
  407. else {
  408. deb = cmd;
  409. length = 0;
  410. delim = ' ';
  411. }
  412. }
  413. //Fin d'un mot
  414. else if(*cmd == delim && chercheFin){
  415. chercheFin = false;
  416. //Recup le mot
  417. c->argv[i] = malloc(sizeof(char) * (length + 1));
  418. memset(c->argv[i], 0, length + 1);
  419. strncpy(c->argv[i++], deb, length);
  420. }
  421. //Incremente
  422. cmd++;
  423. length++;
  424. }
  425. //Recup le dernier mot si besoin
  426. if(chercheFin){
  427. c->argv[i] = malloc(sizeof(char) * (length + 1));
  428. memset(c->argv[i], 0, length + 1);
  429. strncpy(c->argv[i++], deb, length);
  430. }
  431. //Set la dernière case du tableau à null
  432. c->argv[i] = NULL;
  433. return SHELL_OK;
  434. }
  435. /* --- Fonctions publiques --- */
  436. int parse_line(CommandTab* ct, char* line){
  437. //Declaration variable
  438. int compteur, tmp;
  439. //Nettoyage ligne
  440. line = trim(mtrim(line, '\n'));
  441. //Compte le nombre de commande dans la ligne
  442. compteur = nb_commands(line);
  443. if(compteur == SHELL_ERR){
  444. return SHELL_ERR;
  445. }
  446. //Initialisation structure
  447. ct->cmd = malloc(sizeof(Command*) * compteur);
  448. ct->length = compteur;
  449. ct->bck = line[strlen(line) - 1] == '&';
  450. //Si il y a un un & on le retire (on à deja l'information)
  451. if(ct->bck){
  452. line[strlen(line) - 1] = '\0';
  453. }
  454. //Recupération de chaque commande
  455. for(int i = 0; i < compteur; i++){
  456. ct->cmd[i] = malloc(sizeof(Command));
  457. tmp = get_command(ct->cmd[i], line);
  458. line += tmp;
  459. //Si pas dernière commande on trim
  460. if(i + 1 < compteur){
  461. line = ltrim(line, ' ');
  462. }
  463. }
  464. //Retour
  465. return SHELL_OK;
  466. }
  467. int parse_command(Command* c){
  468. //Declaration variable
  469. int length, nbWildcard = 0, res;
  470. char* cmd, **wildcardTab;
  471. //Parse les redirections
  472. length = set_redirection(c);
  473. if(length == SHELL_ERR || length == 0){
  474. return SHELL_ERR;
  475. }
  476. //Recup la commande (sans redirection)
  477. cmd = malloc(sizeof(char) * (length + 1));
  478. memset(cmd, 0, length + 1);
  479. strncpy(cmd, c->cmd, length);
  480. //Split la commande
  481. split_command(c, cmd);
  482. c->name = c->argv[0];
  483. //Analyse wildcard
  484. for(int i = 0; i < c->argc; i++){
  485. //Regarde si il faut remplacer l'argument par une suite de fichier
  486. nbWildcard = wildcard_result(c->argv[i]);
  487. printf("NbWildcard %s [%d] : %d\n", c->argv[i], i, nbWildcard);
  488. if(nbWildcard > 0){
  489. //Si il y a des resultats on prepare un tableau pour les récupérer
  490. wildcardTab = malloc(sizeof(char*) * nbWildcard);
  491. nbWildcard = wildcard(c->argv[i], nbWildcard, wildcardTab);
  492. printf("NbWildcard 2 %s [%d] : %d\n", c->argv[i], i, nbWildcard);
  493. for(int j = 0; j < nbWildcard; j++){
  494. printf("Fichier : %s\n", wildcardTab[j]);
  495. }
  496. //Verif retour
  497. if(nbWildcard == ERR){
  498. return SHELL_ERR;
  499. }
  500. //Ajoute les wildcard dans argv (le +1 est la pour garder le NULL à la fin)
  501. c->argv = insert_array(i, c->argv, c->argc + 1, wildcardTab, nbWildcard, &res);
  502. if(res == ERR){
  503. return SHELL_ERR;
  504. }
  505. c->argc = res - 1; //On ne compte pas le NULL final
  506. }
  507. }
  508. //Ici tous est ok
  509. return SHELL_OK;
  510. }
  511. int parse_all_command(CommandTab* ct){
  512. int tmp;
  513. for(int i = 0; i < ct->length; i++){
  514. tmp = parse_command(ct->cmd[i]);
  515. if(tmp != SHELL_OK){
  516. return SHELL_FAIL;
  517. }
  518. }
  519. return SHELL_OK;
  520. }
  521. void clean_command(CommandTab* ct){
  522. extern int errno;
  523. //Vide le tableau
  524. for(int i = 0; i < ct->length; i++){
  525. //Si la commande a été parsée on vide les arguments
  526. if(ct->cmd[i]->argc > 0){
  527. ct->cmd[i]->name = NULL;
  528. for(int j = 0; j < ct->cmd[i]->argc; j++){
  529. free(ct->cmd[i]->argv[j]);
  530. }
  531. }
  532. //Ferme les fichiers ouverts si besoin
  533. if(ct->cmd[i]->input != STDIN){
  534. if(close(ct->cmd[i]->input)){
  535. fprintf(stderr, "Erreur lors de la fermeture du fichier d'input de %s : %s\n", ct->cmd[i]->cmd, strerror(errno));
  536. }
  537. }
  538. if(ct->cmd[i]->output != STDOUT){
  539. if(close(ct->cmd[i]->output)){
  540. fprintf(stderr, "Erreur lors de la fermeture du fichier d'output de %s : %s\n", ct->cmd[i]->cmd, strerror(errno));
  541. }
  542. }
  543. if(ct->cmd[i]->error != STDERR && ct->cmd[i]->error != ct->cmd[i]->output){ //Verif en plus qu'il est different du fichier de sortie standard (>& et >>&)
  544. if(close(ct->cmd[i]->error)){
  545. fprintf(stderr, "Erreur lors de la fermeture du fichier d'error de %s : %s\n", ct->cmd[i]->cmd, strerror(errno));
  546. }
  547. }
  548. //Supprime la ligne de commande
  549. free(ct->cmd[i]->cmd);
  550. //Supprime la structure
  551. free(ct->cmd[i]);
  552. }
  553. //Met à 0 la taille du tableau
  554. ct->length = 0;
  555. }