diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2011-07-18 13:21:50 +0200 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2011-07-18 13:21:50 +0200 |
commit | 1c813061532c2f664994d10da7ad1449d9ff523d (patch) | |
tree | be9000c9bc687b8d82e9d4588f1116edcc4541ec | |
parent | 8fb00e474e9274ab8840b2fd35c4dc083ddaa3f2 (diff) | |
download | videoteco-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.c | 205 | ||||
-rw-r--r-- | tecexec.c | 21 | ||||
-rw-r--r-- | tecparse.h | 2 | ||||
-rw-r--r-- | tecstate.c | 6 |
4 files changed, 135 insertions, 99 deletions
@@ -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 */ @@ -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 */ @@ -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); @@ -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; |