parser.c 20 KB

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