Browse Source

[enh] Handle 2>&1 fd redirections.
- new f() to handle '&[1-2]' parsing
- duplicate output fd specified
- add unit tests
- rename var to be more explicit

Moul 4 years ago
parent
commit
1a718341da
4 changed files with 59 additions and 21 deletions
  1. 1 1
      README.md
  2. 43 15
      src/redirect.c
  3. 3 2
      src/sh.h
  4. 12 3
      tests.sh

+ 1 - 1
README.md

@@ -72,7 +72,7 @@ Three entries:
  * [ ] Espaces entre les sauts de lignes ?
 
 - Autres :
- * [ ] Gestion 2>&1, 2<&1 : https://stackoverflow.com/questions/818255/in-the-shell-what-does-21-mean
+ * [x] Gestion 2>&1, 2<&1 : https://stackoverflow.com/questions/818255/in-the-shell-what-does-21-mean
  * [ ] copier/coller
   - [ ] vérifier que ça fonctionne sous iTerm
 

+ 43 - 15
src/redirect.c

@@ -3,7 +3,7 @@
 /*
 ** If a chevron is present:
 **  Prevent segfault by checking there is something before and after chevron
-**  Parse redirections: split in three parts:
+**  Parse redirections: split in four parts:
 **  Get position of the first chevron
 **  Before chevron, chevron, after chevron
 **  Check if fd is specified
@@ -15,10 +15,11 @@
 void	parse_redirection(t_e *e, char *str)
 {
 	char	*chev;
-	char	*split[4];
-	int		len;
+//	char	*and;
+	char	**split;
+	int		nchev;
 	int		fd;
-	int		pos;
+	int		chev_pos;
 
 	if ((chev = ft_strchr(str, '<')) != NULL || \
 			(chev = ft_strchr(str, '>')) != NULL)
@@ -28,13 +29,15 @@ void	parse_redirection(t_e *e, char *str)
 			error_message("", "", "nothing specified before or after chevron");
 			return ;
 		}
+		split = (char**)malloc(sizeof(char*) * 4);
 		fd = chev[-1] == '1' || chev[-1] == '2' ? 1 : 0;
-		len = chev[0] == chev[1] ? 2 : 1;
-		pos = ft_strlen(str) - ft_strlen(chev);
-		split[0] = ft_strtrim(ft_strsub(str, 0, pos - fd));
-		split[1] = ft_strtrim(ft_strsub(str, pos - fd, len + fd));
-		split[2] = ft_strtrim(&str[pos + len]);
-		redirections(e, split[0], split[1], split[2]);
+		nchev = chev[0] == chev[1] ? 2 : 1;
+		chev_pos = ft_strlen(str) - ft_strlen(chev);
+		split[0] = ft_strtrim(ft_strsub(str, 0, chev_pos - fd));
+		split[1] = ft_strtrim(ft_strsub(str, chev_pos - fd, nchev + fd));
+		split = parse_and(str, split, chev_pos + nchev);
+//		ft_printf("%s\n%s\n%s\n%s\n", split[0], split[1], split[2], split[3]);
+		redirections(e, split[0], split[1], split[2], split[3]);
 	}
 	else
 		launch_pipe(str);
@@ -55,6 +58,27 @@ int		check_before_after_chevron(char *chev)
 	return (0);
 }
 
+/*
+** Handle splitting if '&[1-2]' is here
+** echo test|2>|tata
+** echo test|2>|&1|tata
+** Check '&[1-2]' presence: andp: and presence
+** If '&' presence: parse one way, else: parse other way
+*/
+
+char	**parse_and(char *str, char **split, int file_pos)
+{
+	char	*and;
+	int	andp;
+
+	andp = ((and = ft_strchr(str, '&')) != NULL && \
+		(and[1] == '0' || and[1] == '1' || \
+		and[1] == '2' || and[1] == '-')) ? 1 : 0;
+	split[2] = andp == 1 ? ft_strsub(and, 1, 1) : NULL;
+	split[3] = andp == 1 ? &and[2] : ft_strtrim(&str[file_pos]);
+	return (split);
+}
+
 /*
 ** if <: open file and dup it in STDIN, save stdfd
 ** elif <<: run bottow function
@@ -64,7 +88,7 @@ int		check_before_after_chevron(char *chev)
 ** if != <<: close fd, restore stdfd
 */
 
-void	redirections(t_e *e, char *cmd, char *operator, char *file)
+void	redirections(t_e *e, char *cmd, char *operator, char *ofd, char *file)
 {
 	int		fd[2];
 
@@ -78,7 +102,7 @@ void	redirections(t_e *e, char *cmd, char *operator, char *file)
 	else if (ft_strcmp(operator, "<<") == 0)
 		prompt_redirection(e, cmd, file);
 	else if (ft_strstr(operator, ">") != NULL)
-		right_redirections(fd, operator, file);
+		right_redirections(fd, operator, ofd, file);
 	if (ft_strcmp(operator, "<<") != 0)
 	{
 		launch_pipe(cmd);
@@ -92,15 +116,19 @@ void	redirections(t_e *e, char *cmd, char *operator, char *file)
 }
 
 /*
-** open, trunc or append, save stdfd, dup new fd in STDIN
+** for file writting: open, append or trunc
+** for fd redirecting: ofd: output fd: dup ofd
+** save stdfd, dup new fd in STDIN
 */
 
-void	right_redirections(int *fd, char *operator, char *file)
+void	right_redirections(int *fd, char *operator, char *ofd, char *file)
 {
 	if (ft_strstr(operator, ">>") != NULL)
 		fd[0] = open(file, O_APPEND | O_WRONLY | O_CREAT, 0644);
-	else
+	else if (ofd == NULL)
 		fd[0] = open(file, O_TRUNC | O_WRONLY | O_CREAT, 0644);
+	else if (ofd != NULL)
+		fd[0] = ofd[0] == '2' ? dup(STDERR) : dup(STDOUT);
 	fd[1] = operator[0] == '2' ? dup(STDERR) : dup(STDOUT);
 	operator[0] == '2' ? dup2(fd[0], STDERR) : dup2(fd[0], STDOUT);
 }

+ 3 - 2
src/sh.h

@@ -29,8 +29,9 @@ void	comma_split(t_e *e, char *cmd);
 */
 void	parse_redirection(t_e *e, char *str);
 int		check_before_after_chevron(char *chev);
-void	redirections(t_e *e, char *cmd, char *operator, char *file);
-void	right_redirections(int *fd, char *operator, char *file);
+char	**parse_and(char *str, char **split, int file_pos);
+void	redirections(t_e *e, char *cmd, char *operator, char *ofd, char *file);
+void	right_redirections(int *fd, char *operator, char *ofd, char *file);
 /*
 ** heredoc.c
 */

+ 12 - 3
tests.sh

@@ -67,8 +67,6 @@ tests=(
 "mkdir 2>> $tmpf; cat $tmpf ; rm $tmpf" # double avec fd2 spécifié et erreur
 "ls 2> $tmpf; cat $tmpf ; rm $tmpf" # simple avec fd2 spécifié sans erreur
 "ls 2>> $tmpf; cat $tmpf ; rm $tmpf" # double avec fd2 spécifié sans erreur
-
-#"cat riri 2>&-" # avec fd spécifiés
 "ls>$tmpf ; cat $tmpf ; rm $tmpf" # collé
 "ls 1> $tmpf ; cat $tmpf" # fd 1 spécifié
 
@@ -77,7 +75,15 @@ tests=(
 #"cat << fin\nnrstai\nfin\n" # double gauche
 #"cat << toto\nnrstai\nrsnati\nairnst\ntoto" # double gauche avec autre string de fin
 
-## Segfault on redirections
+## Redirections avec fd de sortie spécifié
+"echo test 2>&-" # de fd2 dans le vide ? non
+"echo test 1>&2"
+"echo test >&2"
+"echo test 2>&1"
+#"echo test 2>>&1" # create file named "1"
+"echo test 2<&1"
+
+## Segfault and parsing tests on redirections
 ">"
 "ls>"
 "ls >"
@@ -95,6 +101,9 @@ tests=(
 "cat <<"
 "<<end"
 "<< end"
+"echo test 2>&1toto; rm 1toto" # zsh create file named "1toto"
+"echo test2>&1 toto"
+"echo test2>&1toto; rm 1toto" # zsh create file named "1toto"
 
 ## Mix
 "rm $tmpf ; ls ; pwd; ls -a | cat -e | wc > $tmpf ; cat $tmpf ; rm $tmpf" # point-virgules, pipes et redirection