parser.c 19 KB

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