diff --git a/configure.ac b/configure.ac index 6f72b2a..846e292 100644 --- a/configure.ac +++ b/configure.ac @@ -25,7 +25,7 @@ fi dnl Items we can use if present, but can do without if not present. AC_CHECK_FUNCS([getopt_long]) -AC_CHECK_FUNCS([vsnprintf strlcat strtoul]) +AC_CHECK_FUNCS([vsnprintf strlcat strtoul memrchr]) AC_CHECK_FUNCS([fdatasync]) AC_CHECK_FUNCS([fpathconf sysconf posix_memalign posix_fadvise]) AC_CHECK_FUNCS([nanosleep]) diff --git a/src/include/config.h.in b/src/include/config.h.in index 92b0804..f55b9fb 100644 --- a/src/include/config.h.in +++ b/src/include/config.h.in @@ -79,6 +79,9 @@ /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE +/* Define to 1 if you have the `memrchr' function. */ +#undef HAVE_MEMRCHR + /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET diff --git a/src/include/pv.h b/src/include/pv.h index 6063ddf..a2c9132 100644 --- a/src/include/pv.h +++ b/src/include/pv.h @@ -88,6 +88,12 @@ extern size_t pv_strlcat(char *, const char *, size_t); */ /*@null@ */ /*@only@ */ extern char *pv_strdup(const char *); +/* + * Return a pointer to the last matching character in the buffer, or NULL if + * not found. + */ +/*@null@ */ /*@temp@ */ extern void *pv_memrchr(const void *, int, size_t); + /* * Functions relating to elapsed time. */ diff --git a/src/pv/string.c b/src/pv/string.c index a9d8eb1..2b511c2 100644 --- a/src/pv/string.c +++ b/src/pv/string.c @@ -151,4 +151,33 @@ char *pv_strdup(const char *original) return duplicate; } +/* + * Return a pointer to the last matching character in the buffer, or NULL if + * not found. + */ +/*@null@ */ +/*@temp@ */ +void *pv_memrchr(const void *buffer, int match, size_t length) +{ +#ifdef HAVE_MEMRCHR + /*@-unrecog @*/ /* splint doesn't know of memrchr() */ + return memrchr(buffer, match, length); + /*@+unrecog @*/ +#else + unsigned char *ptr; + + if (length < 1) + return NULL; + + ptr = ((unsigned char *) buffer) + length - 1; + while (ptr >= (unsigned char *) buffer) { + if ((int) (ptr[0]) == match) + return (void *) ptr; + ptr--; + } + + return NULL; +#endif +} + /* EOF */ diff --git a/src/pv/transfer.c b/src/pv/transfer.c index 6c2861e..033e4ff 100644 --- a/src/pv/transfer.c +++ b/src/pv/transfer.c @@ -655,32 +655,24 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long * Write returned >0 - data successfully written. */ if ((state->linemode) && (lineswritten != NULL)) { - /* - * Guillaume Marcais: use strchr to count \n - */ - char save; + char separator; char *ptr; long lines = 0; - save = state->transfer_buffer[state->write_position + nwritten]; - state->transfer_buffer[state->write_position + nwritten] = '\0'; - ptr = (char *) (state->transfer_buffer + state->write_position - 1); - if (state->null_terminated_lines) { - for (ptr++; - ptr - - (char *) state->transfer_buffer - - state->write_position < (size_t) nwritten; ptr++) { - if (*ptr == '\0') - ++lines; - } + separator = '\0'; } else { - while ((ptr = strchr((char *) (ptr + 1), '\n'))) + separator = '\n'; + } + + ptr = (char *) (state->transfer_buffer + state->write_position - 1); + for (ptr++; + ptr - (char *) state->transfer_buffer - state->write_position < (size_t) nwritten; ptr++) { + if (*ptr == separator) ++lines; } *lineswritten += lines; - state->transfer_buffer[state->write_position + nwritten] = save; } state->write_position += nwritten; @@ -1010,22 +1002,14 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t * so that we're writing output line-by-line. */ if ((state->to_write > 0) && (state->linemode) && !(state->null_terminated_lines)) { - /* - * Guillaume Marcais: use strrchr to find last \n - */ - char save; char *start; char *end; - save = state->transfer_buffer[state->write_position + state->to_write]; - state->transfer_buffer[state->write_position + state->to_write] = '\0'; - start = (char *) (state->transfer_buffer + state->write_position); - end = strrchr(start, '\n'); - state->transfer_buffer[state->write_position + state->to_write] = save; + end = pv_memrchr(start, (int) '\n', (size_t) (state->to_write)); - if (end != NULL) { - state->to_write = (end - start) + 1; + if (NULL != end) { + state->to_write = (ssize_t) ((end - start) + 1); } }