3 * @brief Dynamic buffer module
8 /******************************************************************************/
12 * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
14 * This software is distributed under commercial and open source licenses.
15 * You may use the GPL open source license described below or you may acquire
16 * a commercial license from Mbedthis Software. You agree to be fully bound
17 * by the terms of either license. Consult the LICENSE.TXT distributed with
18 * this software for full details.
20 * This software is open source; you can redistribute it and/or modify it
21 * under the terms of the GNU General Public License as published by the
22 * Free Software Foundation; either version 2 of the License, or (at your
23 * option) any later version. See the GNU General Public License for more
24 * details at: http://www.mbedthis.com/downloads/gplLicense.html
26 * This program is distributed WITHOUT ANY WARRANTY; without even the
27 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
29 * This GPL license does NOT permit incorporating this software into
30 * proprietary programs. If you are unable to comply with the GPL, you must
31 * acquire a commercial license to use this software. Commercial licenses
32 * for this software and support services are available from Mbedthis
33 * Software at http://www.mbedthis.com
39 /********************************** Includes **********************************/
43 /**************************** Forward Declarations ****************************/
45 static int grow(MprBuf *bp);
47 /*********************************** Code *************************************/
49 * Create a new buffer. "maxsize" is the limit to which the buffer can
50 * ever grow. -1 means no limit. The buffer can ever only fix maxsize-1 bytes.
51 * "initialSize" is used to define the amount to increase the size of the
52 * buffer each time if it becomes full. (Note: grow() will exponentially
53 * increase this number for performance.)
56 MprBuf *mprCreateBuf(MprCtx ctx, int initialSize, int maxSize)
60 if (initialSize <= 0) {
61 initialSize = MPR_DEFAULT_ALLOC;
63 bp = mprAllocTypeZeroed(ctx, MprBuf);
64 bp->growBy = MPR_BUFSIZE;
66 mprSetBufSize(bp, initialSize, maxSize);
70 /******************************************************************************/
72 * Set the initial buffer parameters and create the first buffer
75 void mprSetBufSize(MprBuf *bp, int initialSize, int max)
77 mprAssert(initialSize > 0);
79 if (max > 0 && initialSize > max) {
83 if (bp->buf && bp->growBy > 0) {
87 bp->buf = (uchar*) mprAlloc(bp, initialSize);
88 bp->growBy = initialSize;
90 bp->buflen = initialSize;
91 bp->endbuf = &bp->buf[bp->buflen];
97 /******************************************************************************/
99 char *mprStealBuf(MprCtx ctx, MprBuf *bp)
103 str = (char*) bp->start;
105 mprStealAllocBlock(MPR_LOC_ARGS(ctx), bp->start);
107 bp->start = bp->end = bp->buf = bp->endbuf = 0;
113 /******************************************************************************/
115 void mprAddNullToBuf(MprBuf *bp)
117 *((char*) bp->end) = (char) '\0';
120 /******************************************************************************/
122 void mprAdjustBufEnd(MprBuf *bp, int size)
124 mprAssert(bp->buflen == (bp->endbuf - bp->buf));
125 mprAssert(size < bp->buflen);
128 if (bp->end >= bp->endbuf) {
129 bp->end -= bp->buflen;
131 if (bp->end < bp->buf) {
132 bp->end += bp->buflen;
135 if (bp->end >= bp->endbuf) {
136 mprAssert(bp->end < bp->endbuf);
141 /******************************************************************************/
143 * Adjust the start pointer after a user copy
146 void mprAdjustBufStart(MprBuf *bp, int size)
148 mprAssert(bp->buflen == (bp->endbuf - bp->buf));
149 mprAssert(size < bp->buflen);
152 while (bp->start >= bp->endbuf) {
153 bp->start -= bp->buflen;
155 while (bp->start < bp->buf) {
156 bp->start += bp->buflen;
160 * Flush the buffer if the start pointer is corrupted via a bad size
162 if (bp->start >= bp->endbuf) {
163 mprAssert(bp->start < bp->endbuf);
169 /******************************************************************************/
171 void mprFlushBuf(MprBuf *bp)
177 /******************************************************************************/
179 int mprGetCharFromBuf(MprBuf *bp)
183 if (bp->start == bp->end) {
186 c = (uchar) *bp->start++;
187 if (bp->start >= bp->endbuf) {
193 /******************************************************************************/
195 int mprGetBlockFromBuf(MprBuf *bp, uchar *buf, int size)
197 int thisLen, bytesRead;
201 mprAssert(bp->buflen == (bp->endbuf - bp->buf));
204 * Get the max bytes in a straight copy
208 thisLen = mprGetBufLinearData(bp);
209 thisLen = min(thisLen, size);
214 memcpy(buf, bp->start, thisLen);
216 bp->start += thisLen;
218 bytesRead += thisLen;
220 if (bp->start >= bp->endbuf) {
227 /******************************************************************************/
229 int mprGetBufLength(MprBuf *bp)
231 if (bp->start > bp->end) {
232 return (bp->buflen + (bp->end - bp->start));
234 return (bp->end - bp->start);
238 /******************************************************************************/
240 int mprGetBufLinearData(MprBuf *bp)
242 return min(mprGetBufLength(bp), (bp->endbuf - bp->start));
245 /******************************************************************************/
247 int mprGetBufLinearSpace(MprBuf *bp)
249 int len = mprGetBufLength(bp);
250 int space = bp->buflen - len - 1;
251 return min((bp->endbuf - bp->end), space);
254 /******************************************************************************/
256 int mprGetBufSize(MprBuf *bp)
261 /******************************************************************************/
263 int mprGetBufSpace(MprBuf *bp)
265 return bp->buflen - mprGetBufLength(bp) - 1;
268 /******************************************************************************/
270 char *mprGetBufOrigin(MprBuf *bp)
272 return (char*) bp->buf;
275 /******************************************************************************/
277 char *mprGetBufStart(MprBuf *bp)
279 return (char*) bp->start;
282 /******************************************************************************/
284 char *mprGetBufEnd(MprBuf *bp)
286 return (char*) bp->end;
289 /******************************************************************************/
291 int mprInsertCharToBuf(MprBuf *bp, int c)
296 mprAssert(bp->buflen == (bp->endbuf - bp->buf));
298 space = bp->buflen - mprGetBufLength(bp) - 1;
299 if (space < (int) sizeof(char)) {
304 if (bp->start <= bp->buf) {
305 bp->start = bp->endbuf;
307 cp = (char*) bp->start;
309 bp->start = (uchar *) cp;
313 /******************************************************************************/
315 int mprLookAtNextCharInBuf(MprBuf *bp)
317 if (bp->start == bp->end) {
323 /******************************************************************************/
325 int mprLookAtLastCharInBuf(MprBuf *bp)
327 if (bp->start == bp->end) {
330 return (bp->end == bp->buf) ? bp->endbuf[-1] : bp->end[-1];
333 /******************************************************************************/
335 int mprPutCharToBuf(MprBuf *bp, int c)
340 mprAssert(bp->buflen == (bp->endbuf - bp->buf));
342 space = bp->buflen - mprGetBufLength(bp) - 1;
343 if (space < (int) sizeof(char)) {
349 cp = (char*) bp->end;
351 bp->end = (uchar *) cp;
352 if (bp->end >= bp->endbuf) {
355 *((char*) bp->end) = (char) '\0';
359 /******************************************************************************/
361 int mprPutBlockToBuf(MprBuf *bp, const char *str, int size)
363 int thisLen, bytes, space;
366 mprAssert(size >= 0);
367 mprAssert(bp->buflen == (bp->endbuf - bp->buf));
370 * Add the max we can in one copy
374 space = mprGetBufLinearSpace(bp);
375 thisLen = min(space, size);
380 space = mprGetBufLinearSpace(bp);
381 thisLen = min(space, size);
384 memcpy(bp->end, str, thisLen);
390 if (bp->end >= bp->endbuf) {
394 *((char*) bp->end) = (char) '\0';
398 /******************************************************************************/
400 int mprPutStringToBuf(MprBuf *bp, const char *str)
402 return mprPutBlockToBuf(bp, str, strlen(str));
405 /******************************************************************************/
407 int mprPutFmtStringToBuf(MprBuf *bp, const char *fmt, ...)
414 space = mprGetBufLinearSpace(bp);
417 * Add max that the buffer can grow
419 space += (bp->maxsize - bp->buflen - 1);
421 len = mprAllocVsprintf(MPR_LOC_ARGS(bp), &buf, space, fmt, ap);
422 rc = mprPutBlockToBuf(bp, buf, len);
429 /******************************************************************************/
431 * Grow the buffer to fit new data. Return 1 if the buffer can grow.
432 * Grow using the growBy size specified when creating the buffer.
435 static int grow(MprBuf *bp)
439 if (bp->maxsize > 0 && bp->buflen >= bp->maxsize) {
443 newbuf = (uchar*) mprAlloc(bp, bp->buflen + bp->growBy);
445 memcpy(newbuf, bp->buf, bp->buflen);
449 bp->buflen += bp->growBy;
450 bp->end = newbuf + (bp->end - bp->buf);
451 bp->start = newbuf + (bp->start - bp->buf);
453 bp->endbuf = &bp->buf[bp->buflen];
456 * Increase growBy to reduce overhead
459 if (bp->maxsize > 0 && (bp->buflen + bp->growBy) > bp->maxsize) {
460 bp->growBy = bp->maxsize - bp->buflen;
465 /******************************************************************************/
467 * Add a number to the buffer (always null terminated).
470 int mprPutIntToBuf(MprBuf *bp, int i)
475 mprItoa(numBuf, sizeof(numBuf), i);
476 rc = mprPutStringToBuf(bp, numBuf);
477 *((char*) bp->end) = (char) '\0';
482 /******************************************************************************/
484 void mprCopyBufDown(MprBuf *bp)
486 if (mprGetBufLength(bp) == 0) {
490 memmove(bp->buf, bp->start, (bp->end - bp->start));
491 bp->end -= (bp->start - bp->buf);
495 /******************************************************************************/
497 MprBufProc mprGetBufRefillProc(MprBuf *bp)
499 return bp->refillProc;
502 /******************************************************************************/
504 void mprSetBufRefillProc(MprBuf *bp, MprBufProc fn, void *arg)
510 /******************************************************************************/
512 int mprRefillBuf(MprBuf *bp)
514 return (bp->refillProc) ? (bp->refillProc)(bp, bp->refillArg) : 0;
517 /******************************************************************************/
519 void mprResetBufIfEmpty(MprBuf *bp)
521 if (mprGetBufLength(bp) == 0) {
526 /******************************************************************************/
533 * vim600: sw=4 ts=4 fdm=marker