mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-09 00:53:16 +00:00
* Merged version 2.1 of GoAhead webserver. This update was submitted by Antti P Miettinen <antti.p.miettinen@nokia.com>. * NOTES, base64.c, ejIntrn.h, emfdb.c, emfdb.h, md5.h, md5c.c, um.c, um.h: New files. * wbase64.c: Removed. * Makefile.am, asp.c, balloc.c, default.c, ej.h, ejlex.c, ejparse.c, form.c, h.c, handler.c, mime.c, misc.c, ringq.c, rom.c, security.c, socket.c, sym.c, uemf.c, uemf.h, url.c, value.c, webcomp.c, webmain.c, webpage.c, webrom.c, webs.c, webs.h, websuemf.c, wsIntrn.h: Modified.
583 lines
14 KiB
C
583 lines
14 KiB
C
/*
|
|
* ringq.c -- Ring queue buffering module
|
|
*
|
|
* Copyright (c) GoAhead Software Inc., 1995-2000. 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 efficient
|
|
* 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 filler's responsibility to ensure
|
|
* the ringq is never filled such that servp == endp.
|
|
*
|
|
* It is the filler's 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 ringqGrow(ringq_t *rq);
|
|
static int getBinBlockSize(int size);
|
|
|
|
int ringqGrowCalls = 0;
|
|
|
|
/*********************************** 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 initSize, int maxsize)
|
|
{
|
|
int increment;
|
|
|
|
a_assert(rq);
|
|
a_assert(initSize >= 0);
|
|
|
|
increment = getBinBlockSize(initSize);
|
|
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 data in 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)) && !ringqGrow(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) && !ringqGrow(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 null (maybe 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;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Add a null terminator. This does NOT increase the size of the queue
|
|
*/
|
|
|
|
void ringqAddNull(ringq_t *rq)
|
|
{
|
|
a_assert(rq);
|
|
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
|
|
|
*((char_t*) rq->endp) = (char_t) '\0';
|
|
}
|
|
|
|
/******************************************************************************/
|
|
#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 && !ringqGrow(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 && !ringqGrow(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 (! ringqGrow(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);
|
|
a_assert(rq->servp);
|
|
|
|
rq->servp = rq->buf;
|
|
rq->endp = rq->buf;
|
|
if (rq->servp) {
|
|
*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 ringqGrow(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);
|
|
|
|
/*
|
|
* Double the increment so the next grow will line up with balloc'ed memory
|
|
*/
|
|
rq->increment = getBinBlockSize(2 * rq->increment);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Find the smallest binary memory size that "size" will fit into. This
|
|
* makes the ringq and ringqGrow routines much more efficient. The balloc
|
|
* routine likes powers of 2 minus 1.
|
|
*/
|
|
|
|
static int getBinBlockSize(int size)
|
|
{
|
|
int q;
|
|
|
|
size = size >> B_SHIFT;
|
|
for (q = 0; size; size >>= 1) {
|
|
q++;
|
|
}
|
|
return (1 << (B_SHIFT + q));
|
|
}
|
|
|
|
/******************************************************************************/
|