Merge Samba3 and Samba4 together
[amitay/samba.git] / source4 / lib / appweb / ejs-2.0 / mpr / mprBuf.c
1 /**
2  *      @file   mprBuf.c
3  *      @brief  Dynamic buffer module
4  *      @overview 
5  *      @remarks 
6  */
7
8 /******************************************************************************/
9 /*
10  *      @copy   default
11  *      
12  *      Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
13  *      
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.
19  *      
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
25  *      
26  *      This program is distributed WITHOUT ANY WARRANTY; without even the 
27  *      implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
28  *      
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 
34  *      
35  *      @end
36  */
37
38
39 /********************************** Includes **********************************/
40
41 #include        "mpr.h"
42
43 /**************************** Forward Declarations ****************************/
44
45 static int grow(MprBuf *bp);
46
47 /*********************************** Code *************************************/
48 /*
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.)
54  */
55
56 MprBuf *mprCreateBuf(MprCtx ctx, int initialSize, int maxSize)
57 {
58         MprBuf          *bp;
59         
60         if (initialSize <= 0) {
61                 initialSize = MPR_DEFAULT_ALLOC;
62         }
63         bp = mprAllocTypeZeroed(ctx, MprBuf);
64         bp->growBy = MPR_BUFSIZE;
65         bp->maxsize = 0;
66         mprSetBufSize(bp, initialSize, maxSize);
67         return bp;
68 }
69
70 /******************************************************************************/
71 /*
72  *      Set the initial buffer parameters and create the first buffer
73  */
74
75 void mprSetBufSize(MprBuf *bp, int initialSize, int max)
76 {
77         mprAssert(initialSize > 0);
78
79         if (max > 0 && initialSize > max) {
80                 initialSize = max;
81         }
82
83         if (bp->buf && bp->growBy > 0) {
84                 mprFree(bp->buf);
85         }
86
87         bp->buf = (uchar*) mprAlloc(bp, initialSize);
88         bp->growBy = initialSize;
89         bp->maxsize = max;
90         bp->buflen = initialSize;
91         bp->endbuf = &bp->buf[bp->buflen];
92         bp->start = bp->buf;
93         bp->end = bp->buf;
94         *bp->start = '\0';
95 }
96
97 /******************************************************************************/
98
99 char *mprStealBuf(MprCtx ctx, MprBuf *bp)
100 {
101         char    *str;
102
103         str = (char*) bp->start;
104
105         mprStealAllocBlock(MPR_LOC_ARGS(ctx), bp->start);
106
107         bp->start = bp->end = bp->buf = bp->endbuf = 0;
108         bp->buflen = 0;
109
110         return str;
111 }
112
113 /******************************************************************************/
114
115 void mprAddNullToBuf(MprBuf *bp)
116 {
117         *((char*) bp->end) = (char) '\0';
118 }
119
120 /******************************************************************************/
121
122 void mprAdjustBufEnd(MprBuf *bp, int size)
123 {
124         mprAssert(bp->buflen == (bp->endbuf - bp->buf));
125         mprAssert(size < bp->buflen);
126
127         bp->end += size;
128         if (bp->end >= bp->endbuf) {
129                 bp->end -= bp->buflen;
130         }
131         if (bp->end < bp->buf) {
132                 bp->end += bp->buflen;
133         }
134
135         if (bp->end >= bp->endbuf) {
136                 mprAssert(bp->end < bp->endbuf);
137                 mprFlushBuf(bp);
138         }
139 }
140
141 /******************************************************************************/
142 /*
143  *      Adjust the start pointer after a user copy
144  */
145
146 void mprAdjustBufStart(MprBuf *bp, int size)
147 {
148         mprAssert(bp->buflen == (bp->endbuf - bp->buf));
149         mprAssert(size < bp->buflen);
150
151         bp->start += size;
152         while (bp->start >= bp->endbuf) {
153                 bp->start -= bp->buflen;
154         }
155         while (bp->start < bp->buf) {
156                 bp->start += bp->buflen;
157         }
158
159         /*
160          *      Flush the buffer if the start pointer is corrupted via a bad size 
161          */
162         if (bp->start >= bp->endbuf) {
163                 mprAssert(bp->start < bp->endbuf);
164                 mprFlushBuf(bp);
165         }
166 }
167
168
169 /******************************************************************************/
170
171 void mprFlushBuf(MprBuf *bp)
172 {
173         bp->start = bp->buf;
174         bp->end = bp->buf;
175 }
176
177 /******************************************************************************/
178
179 int mprGetCharFromBuf(MprBuf *bp)
180 {
181         int             c;
182
183         if (bp->start == bp->end) {
184                 return -1;
185         }
186         c = (uchar) *bp->start++;
187         if (bp->start >= bp->endbuf) {
188                 bp->start = bp->buf;
189         }
190         return c;
191 }
192
193 /******************************************************************************/
194
195 int mprGetBlockFromBuf(MprBuf *bp, uchar *buf, int size)
196 {
197         int             thisLen, bytesRead;
198
199         mprAssert(buf);
200         mprAssert(size > 0);
201         mprAssert(bp->buflen == (bp->endbuf - bp->buf));
202
203         /*
204          *      Get the max bytes in a straight copy
205          */
206         bytesRead = 0;
207         while (size > 0) {
208                 thisLen = mprGetBufLinearData(bp);
209                 thisLen = min(thisLen, size);
210                 if (thisLen <= 0) {
211                         break;
212                 }
213
214                 memcpy(buf, bp->start, thisLen);
215                 buf += thisLen;
216                 bp->start += thisLen;
217                 size -= thisLen;
218                 bytesRead += thisLen;
219
220                 if (bp->start >= bp->endbuf) {
221                         bp->start = bp->buf;
222                 }
223         }
224         return bytesRead;
225 }
226
227 /******************************************************************************/
228
229 int mprGetBufLength(MprBuf *bp)
230 {
231         if (bp->start > bp->end) {
232                 return (bp->buflen + (bp->end - bp->start));
233         } else {
234                 return (bp->end - bp->start);
235         }
236 }
237
238 /******************************************************************************/
239
240 int mprGetBufLinearData(MprBuf *bp)
241 {
242         return min(mprGetBufLength(bp), (bp->endbuf - bp->start));
243 }
244
245 /******************************************************************************/
246
247 int mprGetBufLinearSpace(MprBuf *bp)
248 {
249         int len = mprGetBufLength(bp);
250         int space = bp->buflen - len - 1;
251         return min((bp->endbuf - bp->end), space);
252 }
253
254 /******************************************************************************/
255
256 int mprGetBufSize(MprBuf *bp)
257 {
258         return bp->buflen;
259 }
260
261 /******************************************************************************/
262
263 int mprGetBufSpace(MprBuf *bp)
264 {
265         return bp->buflen - mprGetBufLength(bp) - 1;
266 }
267
268 /******************************************************************************/
269
270 char *mprGetBufOrigin(MprBuf *bp)
271 {
272         return (char*) bp->buf;
273 }
274
275 /******************************************************************************/
276
277 char *mprGetBufStart(MprBuf *bp)
278 {
279         return (char*) bp->start;
280 }
281
282 /******************************************************************************/
283
284 char *mprGetBufEnd(MprBuf *bp)
285 {
286         return (char*) bp->end;
287 }
288
289 /******************************************************************************/
290
291 int mprInsertCharToBuf(MprBuf *bp, int c)
292 {
293         char    *cp;
294         int             space;
295
296         mprAssert(bp->buflen == (bp->endbuf - bp->buf));
297
298         space = bp->buflen - mprGetBufLength(bp) - 1;
299         if (space < (int) sizeof(char)) {
300                 if (!grow(bp)) {
301                         return -1;
302                 }
303         }
304         if (bp->start <= bp->buf) {
305                 bp->start = bp->endbuf;
306         }
307         cp = (char*) bp->start;
308         *--cp = (char) c;
309         bp->start = (uchar *) cp;
310         return 0;
311 }
312
313 /******************************************************************************/
314
315 int mprLookAtNextCharInBuf(MprBuf *bp)
316 {
317         if (bp->start == bp->end) {
318                 return -1;
319         }
320         return *bp->start;
321 }
322
323 /******************************************************************************/
324
325 int mprLookAtLastCharInBuf(MprBuf *bp)
326 {
327         if (bp->start == bp->end) {
328                 return -1;
329         }
330         return (bp->end == bp->buf) ? bp->endbuf[-1] : bp->end[-1];
331 }
332
333 /******************************************************************************/
334
335 int mprPutCharToBuf(MprBuf *bp, int c)
336 {
337         char    *cp;
338         int             space;
339
340         mprAssert(bp->buflen == (bp->endbuf - bp->buf));
341
342         space = bp->buflen - mprGetBufLength(bp) - 1;
343         if (space < (int) sizeof(char)) {
344                 if (! grow(bp)) {
345                         return -1;
346                 }
347         }
348
349         cp = (char*) bp->end;
350         *cp++ = (char) c;
351         bp->end = (uchar *) cp;
352         if (bp->end >= bp->endbuf) {
353                 bp->end = bp->buf;
354         }
355         *((char*) bp->end) = (char) '\0';
356         return 0;
357 }
358
359 /******************************************************************************/
360
361 int mprPutBlockToBuf(MprBuf *bp, const char *str, int size)
362 {
363         int             thisLen, bytes, space;
364
365         mprAssert(str);
366         mprAssert(size >= 0);
367         mprAssert(bp->buflen == (bp->endbuf - bp->buf));
368
369         /*
370          *      Add the max we can in one copy
371          */
372         bytes = 0;
373         while (size > 0) {
374                 space = mprGetBufLinearSpace(bp);
375                 thisLen = min(space, size);
376                 if (thisLen <= 0) {
377                         if (! grow(bp)) {
378                                 break;
379                         }
380                         space = mprGetBufLinearSpace(bp);
381                         thisLen = min(space, size);
382                 }
383
384                 memcpy(bp->end, str, thisLen);
385                 str += thisLen;
386                 bp->end += thisLen;
387                 size -= thisLen;
388                 bytes += thisLen;
389
390                 if (bp->end >= bp->endbuf) {
391                         bp->end = bp->buf;
392                 }
393         }
394         *((char*) bp->end) = (char) '\0';
395         return bytes;
396 }
397
398 /******************************************************************************/
399
400 int mprPutStringToBuf(MprBuf *bp, const char *str)
401 {
402         return mprPutBlockToBuf(bp, str, strlen(str));
403 }
404
405 /******************************************************************************/
406
407 int mprPutFmtStringToBuf(MprBuf *bp, const char *fmt, ...)
408 {
409         va_list         ap;
410         char            *buf;
411         int                     rc, len, space;
412
413         va_start(ap, fmt);
414         space = mprGetBufLinearSpace(bp);
415
416         /*
417          *      Add max that the buffer can grow 
418          */
419         space += (bp->maxsize - bp->buflen - 1);
420
421         len = mprAllocVsprintf(MPR_LOC_ARGS(bp), &buf, space, fmt, ap);
422         rc = mprPutBlockToBuf(bp, buf, len);
423
424         mprFree(buf);
425         va_end(ap);
426         return rc;
427 }
428
429 /******************************************************************************/
430 /*
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. 
433  */
434
435 static int grow(MprBuf *bp)
436 {
437         uchar   *newbuf;
438
439         if (bp->maxsize > 0 && bp->buflen >= bp->maxsize) {
440                 return 0;
441         }
442
443         newbuf = (uchar*) mprAlloc(bp, bp->buflen + bp->growBy);
444         if (bp->buf) {
445                 memcpy(newbuf, bp->buf, bp->buflen);
446                 mprFree(bp->buf);
447         }
448
449         bp->buflen += bp->growBy;
450         bp->end = newbuf + (bp->end - bp->buf);
451         bp->start = newbuf + (bp->start - bp->buf);
452         bp->buf = newbuf;
453         bp->endbuf = &bp->buf[bp->buflen];
454
455         /*
456          *      Increase growBy to reduce overhead
457          */
458         bp->growBy *= 2;
459         if (bp->maxsize > 0 && (bp->buflen + bp->growBy) > bp->maxsize) {
460                 bp->growBy = bp->maxsize - bp->buflen;
461         }
462         return 1;
463 }
464
465 /******************************************************************************/
466 /*
467  *      Add a number to the buffer (always null terminated).
468  */
469
470 int mprPutIntToBuf(MprBuf *bp, int i)
471 {
472         char    numBuf[16];
473         int             rc;
474
475         mprItoa(numBuf, sizeof(numBuf), i);
476         rc = mprPutStringToBuf(bp, numBuf);
477         *((char*) bp->end) = (char) '\0';
478
479         return rc;
480 }
481
482 /******************************************************************************/
483
484 void mprCopyBufDown(MprBuf *bp)
485 {
486         if (mprGetBufLength(bp) == 0) {
487                 mprFlushBuf(bp);
488                 return;
489         }
490         memmove(bp->buf, bp->start, (bp->end - bp->start));
491         bp->end -= (bp->start - bp->buf);
492         bp->start = bp->buf;
493 }
494
495 /******************************************************************************/
496
497 MprBufProc mprGetBufRefillProc(MprBuf *bp) 
498 {
499         return bp->refillProc;
500 }
501
502 /******************************************************************************/
503
504 void mprSetBufRefillProc(MprBuf *bp, MprBufProc fn, void *arg)
505
506         bp->refillProc = fn; 
507         bp->refillArg = arg; 
508 }
509
510 /******************************************************************************/
511
512 int     mprRefillBuf(MprBuf *bp) 
513
514         return (bp->refillProc) ? (bp->refillProc)(bp, bp->refillArg) : 0; 
515 }
516
517 /******************************************************************************/
518
519 void mprResetBufIfEmpty(MprBuf *bp)
520 {
521         if (mprGetBufLength(bp) == 0) {
522                 mprFlushBuf(bp);
523         }
524 }
525
526 /******************************************************************************/
527 /*
528  * Local variables:
529  * tab-width: 4
530  * c-basic-offset: 4
531  * End:
532  * vim:tw=78
533  * vim600: sw=4 ts=4 fdm=marker
534  * vim<600: sw=4 ts=4
535  */