summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrbb <rbb@13f79535-47bb-0310-9956-ffa450edef68>2000-04-06 21:38:05 +0000
committerrbb <rbb@13f79535-47bb-0310-9956-ffa450edef68>2000-04-06 21:38:05 +0000
commit783189d322cb49b4cc7ac21556125c4691c39aa8 (patch)
tree5fdd76093ac506b1b81bbf527c747463a1686220
parent73523a83e78684d8d03d28293ed3062513e9c93a (diff)
downloadlibapr-783189d322cb49b4cc7ac21556125c4691c39aa8.tar.gz
Make ungetc work with un-buffered files on Unix.
Submitted by: Jon Travis <jtravis@covalent.net> Reviewed by: Ryan Bloom git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@59806 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--file_io/unix/fileio.h1
-rw-r--r--file_io/unix/open.c1
-rw-r--r--file_io/unix/readwrite.c142
-rw-r--r--include/arch/unix/fileio.h1
4 files changed, 88 insertions, 57 deletions
diff --git a/file_io/unix/fileio.h b/file_io/unix/fileio.h
index ce3904f07..fb02590ca 100644
--- a/file_io/unix/fileio.h
+++ b/file_io/unix/fileio.h
@@ -110,6 +110,7 @@ struct ap_file_t {
int eof_hit;
int pipe;
int timeout;
+ int ungetchar; /* Last char provided by an unget op. (-1 = no char)*/
};
struct ap_dir_t {
diff --git a/file_io/unix/open.c b/file_io/unix/open.c
index 13de87429..b5d5880a0 100644
--- a/file_io/unix/open.c
+++ b/file_io/unix/open.c
@@ -116,6 +116,7 @@ ap_status_t ap_open(ap_file_t **new, const char *fname, ap_int32_t flag, ap_fil
(*new)->oflags = oflags;
(*new)->filedes = -1;
(*new)->filehand = NULL;
+ (*new)->ungetchar = -1;
if ((flag & APR_READ) && (flag & APR_WRITE)) {
buf_oflags = ap_pstrdup(cont, "r+");
diff --git a/file_io/unix/readwrite.c b/file_io/unix/readwrite.c
index cce590881..642c08c01 100644
--- a/file_io/unix/readwrite.c
+++ b/file_io/unix/readwrite.c
@@ -54,6 +54,33 @@
#include "fileio.h"
+static ap_status_t wait_for_io_or_timeout(ap_file_t *file, int for_read)
+{
+ struct timeval tv;
+ fd_set fdset;
+ int srv;
+
+ do {
+ FD_ZERO(&fdset);
+ FD_SET(file->filedes, &fdset);
+ tv.tv_sec = file->timeout;
+ tv.tv_usec = 0;
+ srv = select(FD_SETSIZE,
+ for_read ? &fdset : NULL,
+ for_read ? NULL : &fdset,
+ NULL,
+ file->timeout < 0 ? NULL : &tv);
+ } while (srv == -1 && errno == EINTR);
+
+ if (srv == 0) {
+ return APR_TIMEUP;
+ }
+ else if (srv < 0) {
+ return errno;
+ }
+ return APR_SUCCESS;
+}
+
/* ***APRDOC********************************************************
* ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes)
* Read data from the specified file.
@@ -63,11 +90,13 @@
* NOTE: ap_read will read up to the specified number of bytes, but never
* more. If there isn't enough data to fill that number of bytes, all of
* the available data is read. The third argument is modified to reflect the
- * number of bytes read.
+ * number of bytes read. If a char was put back into the stream via
+ * ungetc, it will be the first character returned.
*/
ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes)
{
ap_ssize_t rv;
+ int used_unget = FALSE;
if(thefile == NULL || nbytes == NULL || (buf == NULL && *nbytes != 0))
return APR_EBADARG;
@@ -77,41 +106,31 @@ ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes)
return APR_EBADF;
}
+ if(*nbytes <= 0) {
+ *nbytes = 0;
+ return APR_SUCCESS;
+ }
+
if (thefile->buffered) {
- rv = fread(buf, *nbytes, 1, thefile->filehand);
+ rv = fread(buf, 1, *nbytes, thefile->filehand);
}
else {
+ if(thefile->ungetchar != -1){
+ used_unget = TRUE;
+ *(char *)buf++ = (char)thefile->ungetchar;
+ (*nbytes)--;
+ thefile->ungetchar == -1;
+ }
+
do {
rv = read(thefile->filedes, buf, *nbytes);
} while (rv == -1 && errno == EINTR);
if (rv == -1 && errno == EAGAIN && thefile->timeout != 0) {
- struct timeval *tv;
- fd_set fdset;
- int srv;
-
- do {
- FD_ZERO(&fdset);
- FD_SET(thefile->filedes, &fdset);
- if (thefile->timeout == -1) {
- tv = NULL;
- }
- else {
- tv = ap_palloc(thefile->cntxt, sizeof(struct timeval));
- tv->tv_sec = thefile->timeout;
- tv->tv_usec = 0;
- }
-
- srv = select(FD_SETSIZE, &fdset, NULL, NULL, tv);
- } while (srv == -1 && errno == EINTR);
-
- if (srv == 0) {
- (*nbytes) = 0;
- return APR_TIMEUP;
- }
- else if (srv < 0) {
- (*nbytes) = 0;
- return errno;
+ ap_status_t arv = wait_for_io_or_timeout(thefile, 1);
+ if (arv != APR_SUCCESS) {
+ *nbytes = 0;
+ return arv;
}
else {
do {
@@ -133,6 +152,10 @@ ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes)
return errno;
}
*nbytes = rv;
+ if(used_unget){
+ thefile->ungetchar = -1;
+ *nbytes += 1;
+ }
return APR_SUCCESS;
}
@@ -168,32 +191,10 @@ ap_status_t ap_write(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes)
} while (rv == -1 && errno == EINTR);
if (rv == -1 && errno == EAGAIN && thefile->timeout != 0) {
- struct timeval *tv;
- fd_set fdset;
- int srv;
-
- do {
- FD_ZERO(&fdset);
- FD_SET(thefile->filedes, &fdset);
- if (thefile->timeout == -1) {
- tv = NULL;
- }
- else {
- tv = ap_palloc(thefile->cntxt, sizeof(struct timeval));
- tv->tv_sec = thefile->timeout;
- tv->tv_usec = 0;
- }
-
- srv = select(FD_SETSIZE, NULL, &fdset, NULL, tv);
- } while (srv == -1 && errno == EINTR);
-
- if (srv == 0) {
- (*nbytes) = 0;
- return APR_TIMEUP;
- }
- else if (srv < 0) {
- (*nbytes) = 0;
- return errno;
+ ap_status_t arv = wait_for_io_or_timeout(thefile, 0);
+ if (arv != APR_SUCCESS) {
+ *nbytes = 0;
+ return arv;
}
else {
do {
@@ -281,8 +282,9 @@ ap_status_t ap_ungetc(char ch, ap_file_t *thefile)
return APR_SUCCESS;
}
return errno;
+ } else {
+ thefile->ungetchar = (unsigned char)ch;
}
- /* Not sure what to do in this case. For now, return SUCCESS. */
return APR_SUCCESS;
}
@@ -313,6 +315,12 @@ ap_status_t ap_getc(char *ch, ap_file_t *thefile)
}
return errno;
}
+
+ if(thefile->ungetchar != -1){
+ *ch = (char) thefile->ungetchar;
+ thefile->ungetchar = -1;
+ return APR_SUCCESS;
+ }
rv = read(thefile->filedes, ch, 1);
if (rv == 0) {
thefile->eof_hit = TRUE;
@@ -384,11 +392,14 @@ ap_status_t ap_flush(ap_file_t *thefile)
ap_status_t ap_fgets(char *str, int len, ap_file_t *thefile)
{
ssize_t rv;
- int i;
+ int i, used_unget = FALSE, beg_idx;
if(thefile == NULL || str == NULL || len < 0)
return APR_EBADARG;
+ if(len <= 1) /* as per fgets() */
+ return APR_SUCCESS;
+
if (thefile->buffered) {
if (fgets(str, len, thefile->filehand)) {
return APR_SUCCESS;
@@ -398,10 +409,25 @@ ap_status_t ap_fgets(char *str, int len, ap_file_t *thefile)
}
return errno;
}
- for (i = 0; i < len; i++) {
+
+ if(thefile->ungetchar != -1){
+ str[0] = thefile->ungetchar;
+ used_unget = TRUE;
+ beg_idx = 1;
+ if(str[0] == '\n' || str[0] == '\r'){
+ thefile->ungetchar = -1;
+ str[1] = '\0';
+ return APR_SUCCESS;
+ }
+ } else
+ beg_idx = 0;
+
+ for (i = beg_idx; i < len; i++) {
rv = read(thefile->filedes, &str[i], 1);
if (rv == 0) {
thefile->eof_hit = TRUE;
+ if(used_unget) thefile->filedes = -1;
+ str[i] = '\0';
return APR_EOF;
}
else if (rv != 1) {
@@ -410,6 +436,8 @@ ap_status_t ap_fgets(char *str, int len, ap_file_t *thefile)
if (str[i] == '\n' || str[i] == '\r')
break;
}
+ if(i < len-1)
+ str[i+1] = '\0';
return APR_SUCCESS;
}
diff --git a/include/arch/unix/fileio.h b/include/arch/unix/fileio.h
index ce3904f07..fb02590ca 100644
--- a/include/arch/unix/fileio.h
+++ b/include/arch/unix/fileio.h
@@ -110,6 +110,7 @@ struct ap_file_t {
int eof_hit;
int pipe;
int timeout;
+ int ungetchar; /* Last char provided by an unget op. (-1 = no char)*/
};
struct ap_dir_t {