summaryrefslogtreecommitdiffstats
path: root/cpukit/httpd/ringq.c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1999-10-27 12:50:33 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1999-10-27 12:50:33 +0000
commitc1cdaa0ce8017b075487e6670f89eb4e715258ea (patch)
treed4571a02595d6cf6a24d40d6968d83ece3b7a574 /cpukit/httpd/ringq.c
parentNew files created by split of old imfs_handlers.c. (diff)
downloadrtems-c1cdaa0ce8017b075487e6670f89eb4e715258ea.tar.bz2
Patch from Emmanuel Raguet <raguet@crf.canon.fr> and Eric Valette
<valette@crf.canon.fr> to add a port of the GoAhead web server (httpd) to the RTEMS build tree. They have successfully used this BSP on i386/pc386 and PowerPC/mcp750. Mark and Joel spoke with Nick Berliner <nickb@goahead.com> on 26 Oct 1999 about this port and got verbal approval to include it in RTEMS distributions.
Diffstat (limited to 'cpukit/httpd/ringq.c')
-rw-r--r--cpukit/httpd/ringq.c537
1 files changed, 537 insertions, 0 deletions
diff --git a/cpukit/httpd/ringq.c b/cpukit/httpd/ringq.c
new file mode 100644
index 0000000000..62c4634eef
--- /dev/null
+++ b/cpukit/httpd/ringq.c
@@ -0,0 +1,537 @@
+/*
+ * ringq.c -- Ring queue buffering module
+ *
+ * Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
+ *
+ * See the file "license.txt" for usage and redistribution license requirements
+ */
+
+/******************************** Description *********************************/
+
+/*
+ * A ring queue allows maximum utilization of memory for data storage and is
+ * ideal for input/output buffering. This module provides a highly effecient
+ * implementation and a vehicle for dynamic strings.
+ *
+ * WARNING: This is a public implementation and callers have full access to
+ * the queue structure and pointers. Change this module very carefully.
+ *
+ * This module follows the open/close model.
+ *
+ * Operation of a ringq where rq is a pointer to a ringq :
+ *
+ * rq->buflen contains the size of the buffer.
+ * rq->buf will point to the start of the buffer.
+ * rq->servp will point to the first (un-consumed) data byte.
+ * rq->endp will point to the next free location to which new data is added
+ * rq->endbuf will point to one past the end of the buffer.
+ *
+ * Eg. If the ringq contains the data "abcdef", it might look like :
+ *
+ * +-------------------------------------------------------------------+
+ * | | | | | | | | a | b | c | d | e | f | | | | |
+ * +-------------------------------------------------------------------+
+ * ^ ^ ^ ^
+ * | | | |
+ * rq->buf rq->servp rq->endp rq->enduf
+ *
+ * The queue is empty when servp == endp. This means that the queue will hold
+ * at most rq->buflen -1 bytes. It is the fillers responsibility to ensure
+ * the ringq is never filled such that servp == endp.
+ *
+ * It is the fillers responsibility to "wrap" the endp back to point to
+ * rq->buf when the pointer steps past the end. Correspondingly it is the
+ * consumers responsibility to "wrap" the servp when it steps to rq->endbuf.
+ * The ringqPutc and ringqGetc routines will do this automatically.
+ */
+
+/********************************* Includes ***********************************/
+
+#if UEMF
+ #include "uemf.h"
+#else
+ #include "basic/basicInternal.h"
+#endif
+
+/*********************************** Defines **********************************/
+/*
+ * Faster than a function call
+ */
+
+#define RINGQ_LEN(rq) \
+ ((rq->servp > rq->endp) ? \
+ (rq->buflen + (rq->endp - rq->servp)) : \
+ (rq->endp - rq->servp))
+
+/***************************** Forward Declarations ***************************/
+
+static int ringq_grow(ringq_t *rq);
+
+/*********************************** Code *************************************/
+/*
+ * Create a new ringq. "increment" is the amount to increase the size of the
+ * ringq should it need to grow to accomodate data being added. "maxsize" is
+ * an upper limit (sanity level) beyond which the q must not grow. Set maxsize
+ * to -1 to imply no upper limit. The buffer for the ringq is always
+ * dynamically allocated. Set maxsize
+ */
+
+int ringqOpen(ringq_t *rq, int increment, int maxsize)
+{
+ a_assert(rq);
+ a_assert(increment >= 0);
+
+ if ((rq->buf = balloc(B_L, increment)) == NULL) {
+ return -1;
+ }
+ rq->maxsize = maxsize;
+ rq->buflen = increment;
+ rq->increment = increment;
+ rq->endbuf = &rq->buf[rq->buflen];
+ rq->servp = rq->buf;
+ rq->endp = rq->buf;
+ *rq->servp = '\0';
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Delete a ringq and free the ringq buffer.
+ */
+
+void ringqClose(ringq_t *rq)
+{
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ if (rq == NULL) {
+ return;
+ }
+
+ ringqFlush(rq);
+ bfree(B_L, (char*) rq->buf);
+ rq->buf = NULL;
+}
+
+/******************************************************************************/
+/*
+ * Return the length of the ringq. Users must fill the queue to a high
+ * water mark of at most one less than the queue size.
+ */
+
+int ringqLen(ringq_t *rq)
+{
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ if (rq->servp > rq->endp) {
+ return rq->buflen + rq->endp - rq->servp;
+ }
+ else {
+ return rq->endp - rq->servp;
+ }
+}
+
+/******************************************************************************/
+/*
+ * Get a byte from the queue
+ */
+
+int ringqGetc(ringq_t *rq)
+{
+ char_t c;
+ char_t* cp;
+
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ if (rq->servp == rq->endp) {
+ return -1;
+ }
+
+ cp = (char_t*) rq->servp;
+ c = *cp++;
+ rq->servp = (unsigned char *) cp;
+ if (rq->servp >= rq->endbuf) {
+ rq->servp = rq->buf;
+ }
+ return c;
+}
+
+/******************************************************************************/
+/*
+ * Add a char to the queue. Note if being used to store wide strings
+ * this does not add a trailing '\0'. Grow the q as required.
+ */
+
+int ringqPutc(ringq_t *rq, char_t c)
+{
+ char_t* cp;
+
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ if (ringqPutBlkMax(rq) < (int) sizeof(char_t) && !ringq_grow(rq)) {
+ return -1;
+ }
+
+ cp = (char_t*) rq->endp;
+ *cp++ = (char_t) c;
+ rq->endp = (unsigned char *) cp;
+ if (rq->endp >= rq->endbuf) {
+ rq->endp = rq->buf;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Insert a wide character at the front of the queue
+ */
+
+int ringqInsertc(ringq_t *rq, char_t c)
+{
+ char_t* cp;
+
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ if (ringqPutBlkMax(rq) < (int) sizeof(char_t) && !ringq_grow(rq)) {
+ return -1;
+ }
+ if (rq->servp <= rq->buf) {
+ rq->servp = rq->endbuf;
+ }
+ cp = (char_t*) rq->servp;
+ *--cp = (char_t) c;
+ rq->servp = (unsigned char *) cp;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Add a string to the queue. Add a trailing wide null (two nulls)
+ */
+
+int ringqPutstr(ringq_t *rq, char_t *str)
+{
+ int rc;
+
+ a_assert(rq);
+ a_assert(str);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ rc = ringqPutBlk(rq, (unsigned char*) str, gstrlen(str) * sizeof(char_t));
+ *((char_t*) rq->endp) = (char_t) '\0';
+ return rc;
+}
+
+/******************************************************************************/
+#if UNICODE
+/*
+ * Get a byte from the queue
+ */
+
+int ringqGetcA(ringq_t *rq)
+{
+ unsigned char c;
+
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ if (rq->servp == rq->endp) {
+ return -1;
+ }
+
+ c = *rq->servp++;
+ if (rq->servp >= rq->endbuf) {
+ rq->servp = rq->buf;
+ }
+ return c;
+}
+
+/******************************************************************************/
+/*
+ * Add a byte to the queue. Note if being used to store strings this does not
+ * add a trailing '\0'. Grow the q as required.
+ */
+
+int ringqPutcA(ringq_t *rq, char c)
+{
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ if (ringqPutBlkMax(rq) == 0 && !ringq_grow(rq)) {
+ return -1;
+ }
+
+ *rq->endp++ = (unsigned char) c;
+ if (rq->endp >= rq->endbuf) {
+ rq->endp = rq->buf;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Insert a byte at the front of the queue
+ */
+
+int ringqInsertcA(ringq_t *rq, char c)
+{
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ if (ringqPutBlkMax(rq) == 0 && !ringq_grow(rq)) {
+ return -1;
+ }
+ if (rq->servp <= rq->buf) {
+ rq->servp = rq->endbuf;
+ }
+ *--rq->servp = (unsigned char) c;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Add a string to the queue. Add a trailing null (not really in the q).
+ * ie. beyond the last valid byte.
+ */
+
+int ringqPutstrA(ringq_t *rq, char *str)
+{
+ int rc;
+
+ a_assert(rq);
+ a_assert(str);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ rc = ringqPutBlk(rq, (unsigned char*) str, strlen(str));
+ rq->endp[0] = '\0';
+ return rc;
+}
+
+#endif /* UNICODE */
+/******************************************************************************/
+/*
+ * Add a block of data to the ringq. Return the number of bytes added.
+ * Grow the q as required.
+ */
+
+int ringqPutBlk(ringq_t *rq, unsigned char *buf, int size)
+{
+ int this, bytes_put;
+
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+ a_assert(buf);
+ a_assert(0 <= size);
+
+/*
+ * Loop adding the maximum bytes we can add in a single straight line copy
+ */
+ bytes_put = 0;
+ while (size > 0) {
+ this = min(ringqPutBlkMax(rq), size);
+ if (this <= 0) {
+ if (! ringq_grow(rq)) {
+ break;
+ }
+ this = min(ringqPutBlkMax(rq), size);
+ }
+
+ memcpy(rq->endp, buf, this);
+ buf += this;
+ rq->endp += this;
+ size -= this;
+ bytes_put += this;
+
+ if (rq->endp >= rq->endbuf) {
+ rq->endp = rq->buf;
+ }
+ }
+ return bytes_put;
+}
+
+/******************************************************************************/
+/*
+ * Get a block of data from the ringq. Return the number of bytes returned.
+ */
+
+int ringqGetBlk(ringq_t *rq, unsigned char *buf, int size)
+{
+ int this, bytes_read;
+
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+ a_assert(buf);
+ a_assert(0 <= size && size < rq->buflen);
+
+/*
+ * Loop getting the maximum bytes we can get in a single straight line copy
+ */
+ bytes_read = 0;
+ while (size > 0) {
+ this = ringqGetBlkMax(rq);
+ this = min(this, size);
+ if (this <= 0) {
+ break;
+ }
+
+ memcpy(buf, rq->servp, this);
+ buf += this;
+ rq->servp += this;
+ size -= this;
+ bytes_read += this;
+
+ if (rq->servp >= rq->endbuf) {
+ rq->servp = rq->buf;
+ }
+ }
+ return bytes_read;
+}
+
+/******************************************************************************/
+/*
+ * Return the maximum number of bytes the ring q can accept via a single
+ * block copy. Useful if the user is doing their own data insertion.
+ */
+
+int ringqPutBlkMax(ringq_t *rq)
+{
+ int space, in_a_line;
+
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ space = rq->buflen - RINGQ_LEN(rq) - 1;
+ in_a_line = rq->endbuf - rq->endp;
+
+ return min(in_a_line, space);
+}
+
+/******************************************************************************/
+/*
+ * Return the maximum number of bytes the ring q can provide via a single
+ * block copy. Useful if the user is doing their own data retrieval.
+ */
+
+int ringqGetBlkMax(ringq_t *rq)
+{
+ int len, in_a_line;
+
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+
+ len = RINGQ_LEN(rq);
+ in_a_line = rq->endbuf - rq->servp;
+
+ return min(in_a_line, len);
+}
+
+/******************************************************************************/
+/*
+ * Adjust the endp pointer after the user has copied data into the queue.
+ */
+
+void ringqPutBlkAdj(ringq_t *rq, int size)
+{
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+ a_assert(0 <= size && size < rq->buflen);
+
+ rq->endp += size;
+ if (rq->endp >= rq->endbuf) {
+ rq->endp -= rq->buflen;
+ }
+/*
+ * Flush the queue if the endp pointer is corrupted via a bad size
+ */
+ if (rq->endp >= rq->endbuf) {
+ error(E_L, E_LOG, T("Bad end pointer"));
+ ringqFlush(rq);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Adjust the servp pointer after the user has copied data from the queue.
+ */
+
+void ringqGetBlkAdj(ringq_t *rq, int size)
+{
+ a_assert(rq);
+ a_assert(rq->buflen == (rq->endbuf - rq->buf));
+ a_assert(0 < size && size < rq->buflen);
+
+ rq->servp += size;
+ if (rq->servp >= rq->endbuf) {
+ rq->servp -= rq->buflen;
+ }
+/*
+ * Flush the queue if the servp pointer is corrupted via a bad size
+ */
+ if (rq->servp >= rq->endbuf) {
+ error(E_L, E_LOG, T("Bad serv pointer"));
+ ringqFlush(rq);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Flush all data in a ring q. Reset the pointers.
+ */
+
+void ringqFlush(ringq_t *rq)
+{
+ a_assert(rq);
+
+ rq->servp = rq->buf;
+ rq->endp = rq->buf;
+ *rq->servp = '\0';
+}
+
+/******************************************************************************/
+/*
+ * Grow the buffer. Return true if the buffer can be grown. Grow using
+ * the increment size specified when opening the ringq. Don't grow beyond
+ * the maximum possible size.
+ */
+
+static int ringq_grow(ringq_t *rq)
+{
+ unsigned char *newbuf;
+ int len;
+
+ a_assert(rq);
+
+ if (rq->maxsize >= 0 && rq->buflen >= rq->maxsize) {
+ return 0;
+ }
+
+ len = ringqLen(rq);
+
+ if ((newbuf = balloc(B_L, rq->buflen + rq->increment)) == NULL) {
+ return 0;
+ }
+ ringqGetBlk(rq, newbuf, ringqLen(rq));
+ bfree(B_L, (char*) rq->buf);
+
+#if OLD
+ rq->endp = &newbuf[endp];
+ rq->servp = &newbuf[servp];
+ rq->endbuf = &newbuf[rq->buflen];
+ rq->buf = newbuf;
+#endif
+
+ rq->buflen += rq->increment;
+ rq->endp = newbuf;
+ rq->servp = newbuf;
+ rq->buf = newbuf;
+ rq->endbuf = &rq->buf[rq->buflen];
+
+ ringqPutBlk(rq, newbuf, len);
+ return 1;
+}
+
+/******************************************************************************/