From bbe8e85b77e3942224857bfe4516628e90ba852d Mon Sep 17 00:00:00 2001
From: Piotr Grzybowski <merlin@narsil.org.pl>
Date: Thu, 28 Jun 2018 13:56:15 +0200
Subject: [PATCH] quick and dirty: store result in variable

---
 command.h     |  3 ++-
 execute_cmd.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 make_cmd.c    |  1 +
 parse.y       | 16 ++++++++++++++--
 redir.c       |  7 ++++++-
 5 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/command.h b/command.h
index 8562644..7519123 100644
--- a/command.h
+++ b/command.h
@@ -32,7 +32,7 @@ enum r_instruction {
   r_close_this, r_err_and_out, r_input_output, r_output_force,
   r_duplicating_input_word, r_duplicating_output_word,
   r_move_input, r_move_output, r_move_input_word, r_move_output_word,
-  r_append_err_and_out
+  r_append_err_and_out, r_store_to_variable
 };
 
 /* Redirection flags; values for rflags */
@@ -149,6 +149,7 @@ typedef struct word_list {
 typedef union {
   int dest;			/* Place to redirect REDIRECTOR to, or ... */
   WORD_DESC *filename;		/* filename to redirect to. */
+  WORD_DESC *variable_name;		/* variable to redirect to. */
 } REDIRECTEE;
 
 /* Structure describing a redirection.  If REDIRECTOR is negative, the parser
diff --git a/execute_cmd.c b/execute_cmd.c
index 126a54a..7ece25e 100644
--- a/execute_cmd.c
+++ b/execute_cmd.c
@@ -5112,6 +5112,48 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var,
     }
 }
 
+static long get_file_size(const char *file_name) {
+ int rc;
+ struct stat stats;
+
+ if (file_name==NULL) {
+  return -1;
+ }
+ rc=stat(file_name, &stats);
+ if (rc==0) {
+  return stats.st_size;
+ }
+ return -1;
+}
+
+static char *read_file(char *file_name) {
+ int rc;
+ int fd;
+ char *b;
+ long s=get_file_size(file_name);
+
+ if (s<=0) {
+  return NULL;
+ }
+
+ b=xmalloc(s);
+ if (b==NULL) {
+  return NULL;
+ }
+
+ fd=open(file_name, O_RDONLY);
+ if (fd<0) {
+  return NULL;
+ }
+ rc=read(fd, b, s);
+ if (rc<0) {
+  close(fd);
+  return NULL;
+ }
+ close(fd);
+ return b;
+}
+
 /* Execute a builtin or function in the current shell context.  If BUILTIN
    is non-null, it is the builtin command to execute, otherwise VAR points
    to the body of a function.  WORDS are the command's arguments, REDIRECTS
@@ -5131,12 +5173,18 @@ execute_builtin_or_function (words, builtin, var, redirects,
      int flags;
 {
   int result;
+  SHELL_VAR *result_variable=NULL;
   REDIRECT *saved_undo_list;
 #if defined (PROCESS_SUBSTITUTION)
   int ofifo, nfifo, osize;
   char *ofifo_list;
 #endif
 
+  if (redirects&&redirects->instruction==r_store_to_variable) {
+   //expand_word(s) on redirects->redirectee.variable_name->word ?
+   result_variable=bind_variable(redirects->redirectee.variable_name->word,"result",0);
+  }
+
 #if defined (PROCESS_SUBSTITUTION)
   begin_unwind_frame ("saved_fifos");
   /* If we return, we longjmp and don't get a chance to restore the old
@@ -5182,6 +5230,10 @@ execute_builtin_or_function (words, builtin, var, redirects,
   else
     result = execute_function (var, words, flags, fds_to_close, 0, 0);
 
+  if (result_variable) {
+   bind_variable(result_variable->name,read_file("/tmp/v_save.bash.temp"),0);
+  }
+
   /* We do this before undoing the effects of any redirections. */
   fflush (stdout);
   fpurge (stdout);
diff --git a/make_cmd.c b/make_cmd.c
index ecbbfd6..9578f44 100644
--- a/make_cmd.c
+++ b/make_cmd.c
@@ -697,6 +697,7 @@ make_redirection (source, instruction, dest_and_filename, flags)
   switch (instruction)
     {
 
+    case r_store_to_variable: /* >>> word */
     case r_output_direction:		/* >foo */
     case r_output_force:		/* >| foo */
     case r_err_and_out:			/* &>filename */
diff --git a/parse.y b/parse.y
index 6457782..b15ec3b 100644
--- a/parse.y
+++ b/parse.y
@@ -348,7 +348,7 @@ static FILE *yyerrstream;
 %token <number> NUMBER
 %token <word_list> ARITH_CMD ARITH_FOR_EXPRS
 %token <command> COND_CMD
-%token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND LESS_LESS_LESS
+%token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND LESS_LESS_LESS GREATER_GREATER_GREATER
 %token GREATER_AND SEMI_SEMI SEMI_AND SEMI_SEMI_AND
 %token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER
 %token GREATER_BAR BAR_AND
@@ -583,6 +583,13 @@ redirection:	'>' WORD
 			  redir.filename = $2;
 			  $$ = make_redirection (source, r_reading_string, redir, 0);
 			}
+	|	GREATER_GREATER_GREATER WORD
+			{
+			 source.dest = 1;
+			 redir.filename = NULL;
+    redir.variable_name = $2;
+			 $$ = make_redirection (source, r_store_to_variable, redir, 0);
+			}
 	|	NUMBER LESS_LESS_LESS WORD
 			{
 			  source.dest = $1;
@@ -2180,6 +2187,7 @@ STRING_INT_ALIST other_token_alist[] = {
   { ";;&", SEMI_SEMI_AND },
   { "<<-", LESS_LESS_MINUS },
   { "<<<", LESS_LESS_LESS },
+  { ">>>", GREATER_GREATER_GREATER },
   { "&>", AND_GREATER },
   { "&>>", AND_GREATER_GREATER },
   { "<>", LESS_GREATER },
@@ -2807,7 +2815,7 @@ static int open_brace_count;
   (token == '<' || token == '>' || \
    token == GREATER_GREATER || token == GREATER_BAR || \
    token == LESS_GREATER || token == LESS_LESS_MINUS || \
-   token == LESS_LESS || token == LESS_LESS_LESS || \
+   token == LESS_LESS || token == LESS_LESS_LESS || token == GREATER_GREATER_GREATER || \
    token == LESS_AND || token == GREATER_AND || token == AND_GREATER)
 
 /* Is `token' one that will allow a WORD to be read in a command position?
@@ -3307,6 +3315,10 @@ itrace("shell_getc: bash_input.location.string = `%s'", bash_input.location.stri
 		}
 
 	    case '>':
+       peek_char = shell_getc (1);
+       if MBTEST(peek_char == '>') {
+        return (GREATER_GREATER_GREATER);
+       }
 	      return (GREATER_GREATER);
 
 	    case ';':
diff --git a/redir.c b/redir.c
index f5276dc..6c49d1e 100644
--- a/redir.c
+++ b/redir.c
@@ -729,7 +729,11 @@ do_redirection_internal (redirect, flags)
   REDIRECT *new_redirect;
   REDIRECTEE sd;
 
-  redirectee = redirect->redirectee.filename;
+  if (redirect->instruction==r_store_to_variable) {
+   redirectee = make_bare_word("/tmp/v_save.bash.temp");
+  } else {
+   redirectee = redirect->redirectee.filename;
+  }
   redir_fd = redirect->redirectee.dest;
   redirector = redirect->redirector.dest;
   ri = redirect->instruction;
@@ -823,6 +827,7 @@ do_redirection_internal (redirect, flags)
 
   switch (ri)
     {
+    case r_store_to_variable:
     case r_output_direction:
     case r_appending_to:
     case r_input_direction:
-- 
2.10.0

