parser.c 20 KB

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