Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore
Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_exe.c Log Message: The fork'n'pipe knows line dancing! Er, I mean line buffering. It's slightly different from what raster wanted. I'll update the example next. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.23 retrieving revision 1.24 diff -u -3 -r1.23 -r1.24 --- ecore_exe.c 11 Dec 2005 06:52:07 -0000 1.23 +++ ecore_exe.c 16 Dec 2005 03:36:16 -0000 1.24 @@ -127,12 +127,15 @@ * * This function does the same thing as ecore_exe_run(), but also makes the * standard in and/or out from the child process available for reading or - * writing. To write use ecore_exe_pipe_write(). To read listen to - * ECORE_EVENT_EXE_DATA events (set up a handler). Ecore may buffer read data - * until a newline character if asked for with the @p flags. All data will be - * included in the events (newlines will not be stripped). This will only - * happen if the process is run with ECORE_EXE_PIPE_READ enabled in the flags. - * + * writing. To write use ecore_exe_pipe_write(). To read listen to + * ECORE_EVENT_EXE_DATA events (set up a handler). Ecore may buffer read + * data until a newline character if asked for with the @p flags. All + * data will be included in the events (newlines will be replaced with + * NULLS if line buffered). ECORE_EVENT_EXE_DATA events will only happen + * if the process is run with ECORE_EXE_PIPE_READ enabled in the flags. + * Writing will only be allowed with ECORE_EXE_PIPE_WRITE enabled in the + * flags. + * * @param exe_cmd The command to run with @c /bin/sh. * @param flags The flag parameters for how to deal with inter-process I/O * @param data Data to attach to the returned process handle. @@ -142,6 +145,7 @@ Ecore_Exe * ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data) { +/* FIXME: MAybe we should allow STDERR reading as well. */ Ecore_Exe *exe = NULL; pid_t pid = 0; int readPipe[2] = { -1, -1 }; @@ -658,73 +662,120 @@ exe = data; if ((exe->read_fd_handler) && (ecore_main_fd_handler_active_get(exe->read_fd_handler, ECORE_FD_READ))) { - unsigned char *inbuf = NULL; - int inbuf_num = 0; + unsigned char *inbuf; + int inbuf_num; + + inbuf = exe->read_data_buf; + inbuf_num = exe->read_data_size; + exe->read_data_buf = NULL; + exe->read_data_size = 0; for (;;) { - int num, lost_server; + int num, lost_exe; char buf[READBUFSIZ]; - lost_server = 0; + lost_exe = 0; errno = 0; - if ((num = read(exe->child_fd_read, buf, READBUFSIZ)) < 1) + if ((num = read(exe->child_fd_read, buf, READBUFSIZ)) < 1) /* FIXME: SPEED/SIZE TRADE OFF - add a smaller READBUFSIZE (currently 64k) to inbuf, use that instead of buf, and save ourselves a memcpy(). */ { - lost_server = ((errno == EIO) || - (errno == EBADF) || - (errno == EPIPE) || - (errno == EINVAL) || - (errno == ENOSPC) || - (num == 0)); - /* is num == 0 is right - when the server closes us - * off we will get this (as this is called when select - * tells us there is data to read!) - */ + lost_exe = ((errno == EIO) || + (errno == EBADF) || + (errno == EPIPE) || + (errno == EINVAL) || + (errno == ENOSPC)); if ((errno != EAGAIN) && (errno != EINTR)) perror("_ecore_exe_data_handler() read problem "); } - if (num < 1) - { - if (inbuf) - { - Ecore_Event_Exe_Data *e; + if (num > 0) + { + inbuf = realloc(inbuf, inbuf_num + num); + memcpy(inbuf + inbuf_num, buf, num); + inbuf_num += num; + } + else + { + if (inbuf) + { + Ecore_Event_Exe_Data *e; - e = calloc(1, sizeof(Ecore_Event_Exe_Data)); - if (e) - { - e->exe = exe; - e->data = inbuf; - e->size = inbuf_num; - ecore_event_add(ECORE_EVENT_EXE_DATA, e, + e = calloc(1, sizeof(Ecore_Event_Exe_Data)); + if (e) + { + e->exe = exe; + e->data = inbuf; + e->size = inbuf_num; + + if (exe->flags & ECORE_EXE_PIPE_READ_LINE_BUFFERED) + { + int max = 0; + int count = 0; + int i; + int last = 0; + char *c; + + c = inbuf; + for (i = 0; i < inbuf_num; i++) /* Find the lines. */ + { + if (inbuf[i] == '\n') + { + if (count >= max) + { + max += 10; /* FIXME: Maybe keep track of the largest number of lines ever sent, and add half that many instead of 10. */ + e->lines = realloc(e->lines, sizeof(Ecore_Event_Exe_Data_Line) * (max + 1)); /* Allow room for the NULL termination. */ + } + /* raster said to leave the line endings as line endings, however - + * This is line buffered mode, we are not dealing with binary here, but lines. + * If we are not dealing with binary, we must be dealing with ASCII, unicode, or some other text format. + * Thus the user is most likely gonna deal with this text as strings. + * Thus the user is most likely gonna pass this data to str functions. + * rasters way - the endings are always gonna be '\n'; onefangs way - they will always be '\0' + * We are handing them the string length as a convenience. + * Thus if they really want it in raw format, they can e->lines[i].line[e->lines[i].size - 1] = '\n'; easily enough. + * In the default case, we can do this conversion quicker than the user can, as we already have the index and pointer. + * Let's make it easy on them to use these as standard C strings. + * + * onefang is proud to announce that he has just set a new personal record for the + * most over documentation of a simple assignment statement. B-) + */ + inbuf[i] = '\0'; + e->lines[count].line = c; + e->lines[count].size = i - last; + last = i + 1; + c = &inbuf[last]; + count++; + } + } + if (count == 0) /* No lines to send, cancel the event. */ + { + _ecore_exe_event_exe_data_free(NULL, e); + e = NULL; + } + else /* NULL terminate the array, so that people know where the end is. */ + { + e->lines[count].line = NULL; + e->lines[count].size = 0; + } + if (i > last) /* Partial line left over, save it for next time. */ + { + e->size = last; + exe->read_data_size = i - last; + exe->read_data_buf = malloc(exe->read_data_size); + memcpy(exe->read_data_buf, c, exe->read_data_size); + } + } + + if (e) + ecore_event_add(ECORE_EVENT_EXE_DATA, e, _ecore_exe_event_exe_data_free, NULL); - } - } - if (lost_server) - { - /* we lost our server! */ + } + } + if (lost_exe) ecore_exe_terminate(exe); - return 1; - } - break; - } - else - { - inbuf = realloc(inbuf, inbuf_num + num); - memcpy(inbuf + inbuf_num, buf, num); - inbuf_num += num; - /* FIXME: - * when fd handlers report data - if line buffering is not enabled instantly - * copy data to a exe data event struct and add the event like ecore_con. if - * line buffering is enabled, parse new data block for a \n. if there is - * none, then simply append to read buf. if there are 1 or more, append - * until, and including the first \n, to the existing read buf (if any) then - * generate data event for that. repeat for each other \n found until no \n - * chars are left, then take trailing data (if any) and put in read buf - * waiting for more data. - */ - } - } - } + break; + } + } + } return 1; } @@ -785,7 +836,9 @@ Ecore_Event_Exe_Data *e; e = ev; - if (e->data) free(e->data); + + if (e->lines) free(e->lines); + if (e->data) free(e->data); free(e); } #endif ------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Do you grep through log files for problems? Stop! Download the new AJAX search engine that makes searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click _______________________________________________ enlightenment-cvs mailing list enlightenment-cvs@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-cvs