aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2011-07-18 13:21:50 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2011-07-18 13:21:50 +0200
commit1c813061532c2f664994d10da7ad1449d9ff523d (patch)
treebe9000c9bc687b8d82e9d4588f1116edcc4541ec
parent8fb00e474e9274ab8840b2fd35c4dc083ddaa3f2 (diff)
downloadvideoteco-fork-1c813061532c2f664994d10da7ad1449d9ff523d.tar.gz
revised EC command
unidirectional pipe with no arguments. with one/two arguments, the buffer content is piped into the process and replaced with its output. * fixed error handling, now the child's exit status matters if everything else is OK, as well * colon modifier has standard behaviour of returning the command status
-rw-r--r--teccmd.c205
-rw-r--r--tecexec.c21
-rw-r--r--tecparse.h2
-rw-r--r--tecstate.c6
4 files changed, 135 insertions, 99 deletions
diff --git a/teccmd.c b/teccmd.c
index e1e5a77..3ad5224 100644
--- a/teccmd.c
+++ b/teccmd.c
@@ -1710,130 +1710,165 @@ register int length;
* user to execute operating system commands from within the editor.
*/
int
-cmd_oscmd( struct cmd_token *ct )
+cmd_oscmd(struct cmd_token *uct, int arg_count, int arg1, int arg2, char *cp)
{
-register char *cp;
-int pid,w,status;
-int pipe_desc[2];
-int last_intr_flag;
-int line_cnt;
char tmpbuf[LINE_BUFFER_SIZE];
-char pipebuff[IO_BUFFER_SIZE];
-extern char susp_flag;
-int pipe_buf_flag = 0;
-int buf_pipe[2];
+struct undo_token *ut;
+int olddot;
+int pid;
+int bidir_flag;
+int input_pipe[2], output_pipe[2];
+int _errno;
+int status;
PREAMBLE();
- if(ct->ctx.flags & CTOK_M_COLON_SEEN){
- pipe_buf_flag = 1;
- status = pipe(buf_pipe);
- if (status != 0) {
- error_message("?Error creating buffer pipe");
+ /* TODO: if only arg1 is given, calculate the buffer range */
+ /* FIXME: colon modifier does not return status */
+ bidir_flag = (arg_count == 1 && arg1 != 0) || arg_count == 2;
+
+/*
+ * For bidirectional piping mode, we need an additional input_pipe
+ */
+ if(bidir_flag){
+ if (pipe(input_pipe)) {
+ sprintf(tmpbuf,"?Error creating PIPE: %s",error_text(errno));
+ error_message(tmpbuf);
return(FAIL);
- }
+ }/* End IF */
}/* End IF */
- cp = ct->ctx.carg;
/*
- * Create a PIPE so that we can capture the output of the child process
+ * otherwise the process will not get any input and write both stdout and stderr
+ * to output_pipe
*/
- status = pipe(pipe_desc);
- if(status != 0){
+ if(pipe(output_pipe)){
sprintf(tmpbuf,"?Error creating PIPE: %s",error_text(errno));
error_message(tmpbuf);
return(FAIL);
}/* End IF */
+
/*
* Fork to get a process to run the shell
*/
- if((pid = fork()) == 0){
- if (pipe_buf_flag) {
- close(0); dup(buf_pipe[0]);
- close(buf_pipe[0]);
- close(buf_pipe[1]);
+ pid = fork();
+ _errno = errno;
+ if(pid == 0){
+ if(bidir_flag){
+ close(0); dup(input_pipe[0]);
+ close(1); dup(output_pipe[1]);
+ close(2); dup(output_pipe[1]);
+ close(input_pipe[0]);
+ close(input_pipe[1]);
+ }else{
+ close(1); dup(output_pipe[1]);
+ close(2); dup(output_pipe[1]);
+ close(0);
}
- close(1); dup(pipe_desc[1]);
- close(2); dup(pipe_desc[1]);
- close(pipe_desc[0]);
- close(pipe_desc[1]);
+ close(output_pipe[0]);
+ close(output_pipe[1]);
+
+ /* FIXME: close other file descriptors */
+
execl("/bin/sh","sh","-c",cp,NULL);
- _exit(127);
+ exit(EXIT_FAILURE);
}/* End IF */
+
+/*
+ * Close file descriptors which are no longer needed in the parent process
+ */
+ if(bidir_flag) close(input_pipe[0]);
+ close(output_pipe[1]);
+
if(pid == -1){
- close(pipe_desc[0]);
- close(pipe_desc[1]);
- sprintf(tmpbuf,"?Error performing FORK: %s",error_text(errno));
+ if(bidir_flag) close(input_pipe[1]);
+ close(output_pipe[0]);
+
+ sprintf(tmpbuf,"?Error forking child process: %s",error_text(_errno));
+ error_message(tmpbuf);
return(FAIL);
}/* End IF */
- if (pipe_buf_flag) {
- struct buff_line *tmp_line = curbuf->first_line;
+ if(bidir_flag){
+ status = buff_write(curbuf,input_pipe[1],arg1,arg2);
+ close(input_pipe[1]);
+ if(status == FAIL){
+ close(output_pipe[0]);
+ goto failreap;
+ }/* End If */
- close(buf_pipe[0]);
- while (tmp_line) {
- int n = tmp_line->byte_count;
- char *lb = tmp_line->buffer;
-
- w = write(buf_pipe[1], lb, n);
- while (w > 0) {
- n -= w;
- lb += w;
- if (n == 0)
- break;
- w = write(pipe_desc[1], lb, n);
- }
- tmp_line = tmp_line->next_line;
- }
- close(buf_pipe[1]);
- }
- close(pipe_desc[1]);
+ status = buff_delete_with_undo(uct,curbuf,arg1,arg2-arg1);
+ if(status == FAIL){
+ close(output_pipe[0]);
+ goto failreap;
+ }/* End If */
+ }/* End If */
/*
* Loop reading stuff coming back from the pipe until we get an
* EOF which means the process has finished. Update the screen
* on newlines so the user can see what is going on.
*/
- last_intr_flag = intr_flag;
- line_cnt = 0;
-
- while((w = read(pipe_desc[0],pipebuff,sizeof(pipebuff))) > 0){
-
- buff_insert(curbuf,curbuf->dot,pipebuff,w);
-
- if(intr_flag != last_intr_flag){
- kill(pid,SIGINT);
- last_intr_flag = intr_flag;
- }/* End IF */
-
- if(susp_flag){
- cmd_pause();
- }/* End IF */
-
- cp = pipebuff;
- while(w--){
- if(intr_flag != last_intr_flag) break;
- if(*cp++ == '\n' && line_cnt++ > (term_lines / 4)){
- line_cnt = 0;
- if(tty_input_pending()) break;
- screen_format_windows();
- screen_refresh();
- }/* End IF */
- }/* End While */
-
- }/* End While */
-
- close(pipe_desc[0]);
+ if(bidir_flag){
+ /* TODO: allocate UNDO token for pointer change */
+ olddot = curbuf->dot;
+ curbuf->dot = arg1;
+ }/* End If */
+ ut = allocate_undo_token(uct);
+ if(ut == NULL){
+ close(output_pipe[0]);
+ goto failreap;
+ }/* End If */
+ ut->opcode = UNDO_C_DELETE;
+ ut->carg1 = (char *)curbuf;
+ ut->iarg1 = curbuf->dot;
+
+ status = buff_readfd(curbuf,cp,output_pipe[0]);
+ close(output_pipe[0]);
+ if(status == FAIL) goto failreap;
+
+ ut->iarg2 = curbuf->dot - ut->iarg1;
+
+ if(bidir_flag){
+ curbuf->dot = olddot;
+ if(curbuf->dot >= ut->iarg1) curbuf->dot += ut->iarg2;
+ }/* End If */
+
/*
* The wait here is required so that the process we forked doesn't
* stay around as a zombie.
*/
- status = 0;
- while((w = wait(&status)) != pid && w != -1);
+ if(waitpid(pid,&status,0) == -1){
+ sprintf(tmpbuf,"?Error waiting for child process <%d>: %s",
+ pid,error_text(errno));
+ error_message(tmpbuf);
+ return(FAIL);
+ }/* End If */
+ if (!WIFEXITED(status)){
+ sprintf(tmpbuf,"?Child process <%d> terminated abnormally",
+ pid);
+ error_message(tmpbuf);
+ return(FAIL);
+ }/* End If */
+ if(WEXITSTATUS(status) != EXIT_SUCCESS){
+ sprintf(tmpbuf,"?Child process <%d> terminated with status %d",
+ pid,WEXITSTATUS(status));
+ error_message(tmpbuf);
+ return(FAIL);
+ }/* End If */
return(SUCCESS);
+failreap:
+
+/*
+ * NOTE: error message has already been displayed
+ */
+ kill(pid,SIGKILL);
+ waitpid(pid,NULL,0);
+ return(FAIL);
+
}/* End Routine */
/* END OF UNIX CONDITIONAL CODE */
diff --git a/tecexec.c b/tecexec.c
index 7409d0f..753a853 100644
--- a/tecexec.c
+++ b/tecexec.c
@@ -2426,17 +2426,20 @@ char tmp_buffer[LINE_BUFFER_SIZE],tmp_message[LINE_BUFFER_SIZE];
*/
case EXEC_C_ECCOMMAND:
{/* Local Block */
- int status;
+ register int arg_count = 0;
+ register int status;
- ut = allocate_undo_token(uct);
- if(ut == NULL) return(FAIL);
- ut->opcode = UNDO_C_DELETE;
- ut->carg1 = (char *)curbuf;
- ut->iarg1 = curbuf->dot;
- ut->iarg2 = 0;
+ if(ct->ctx.iarg1_flag == YES) arg_count = 1;
+ if(ct->ctx.iarg2_flag == YES) arg_count = 2;
+
+ status = cmd_oscmd(uct, arg_count, ct->ctx.iarg1, ct->ctx.iarg2,
+ ct->ctx.carg);
+
+ if(ct->ctx.flags & CTOK_M_COLON_SEEN){
+ ct->ctx.tmpval = status;
+ return(SUCCESS);
+ }/* End IF */
- status = cmd_oscmd(ct);
- ut->iarg2 = curbuf->dot - ut->iarg1;
return(status);
}/* End Local Block */
diff --git a/tecparse.h b/tecparse.h
index fcccd25..c3f4f6e 100644
--- a/tecparse.h
+++ b/tecparse.h
@@ -297,7 +297,7 @@ struct undo_token {
#define UNDO_C_SELECT_TAGS 25
#define UNDO_C_SET_EXIT_FLAG 26
-int cmd_oscmd(struct cmd_token *ct);
+int cmd_oscmd(struct cmd_token *, int, int, int, char *);
int buff_insert_from_buffer_with_undo( struct cmd_token *,
struct buff_header *,int,struct buff_header *,int,int);
int buff_delete_with_undo( struct cmd_token *,struct buff_header *,int,int);
diff --git a/tecstate.c b/tecstate.c
index d93fa52..7edd404 100644
--- a/tecstate.c
+++ b/tecstate.c
@@ -822,10 +822,8 @@ register struct cmd_token *oct = NULL;
* into the edit buffer.
*/
case 'C': case 'c':
- if(ct->ctx.iarg1_flag == YES){
- ct->execute_state = EXEC_C_ECCOMMAND;
- ct->ctx.state = STATE_C_INITIALSTATE;
- return;
+ if(ct->ctx.flags & CTOK_M_COLON_SEEN){
+ ct->ctx.flags |= CTOK_M_STATUS_PASSED;
}/* End IF */
ct->ctx.state = STATE_C_STRING;