Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $  | 
3  |  |  *  | 
4  |  |  * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.  | 
5  |  |  * Michael Clark <michael@metaparadigm.com>  | 
6  |  |  *  | 
7  |  |  * This library is free software; you can redistribute it and/or modify  | 
8  |  |  * it under the terms of the MIT license. See COPYING for details.  | 
9  |  |  *  | 
10  |  |  *  | 
11  |  |  * Copyright (c) 2008-2009 Yahoo! Inc.  All rights reserved.  | 
12  |  |  * The copyrights to the contents of this file are licensed under the MIT License  | 
13  |  |  * (https://www.opensource.org/licenses/mit-license.php)  | 
14  |  |  */  | 
15  |  |  | 
16  |  | #include "config.h"  | 
17  |  |  | 
18  |  | #include <errno.h>  | 
19  |  | #include <limits.h>  | 
20  |  | #include <stdio.h>  | 
21  |  | #include <stdlib.h>  | 
22  |  | #include <string.h>  | 
23  |  |  | 
24  |  | #ifdef HAVE_STDARG_H  | 
25  |  | #include <stdarg.h>  | 
26  |  | #else /* !HAVE_STDARG_H */  | 
27  |  | #error Not enough var arg support!  | 
28  |  | #endif /* HAVE_STDARG_H */  | 
29  |  |  | 
30  |  | #include "debug.h"  | 
31  |  | #include "printbuf.h"  | 
32  |  | #include "snprintf_compat.h"  | 
33  |  | #include "vasprintf_compat.h"  | 
34  |  |  | 
35  |  | static int printbuf_extend(struct printbuf *p, int min_size);  | 
36  |  |  | 
37  |  | struct printbuf *printbuf_new(void)  | 
38  | 17.6k  | { | 
39  | 17.6k  |   struct printbuf *p;  | 
40  |  |  | 
41  | 17.6k  |   p = (struct printbuf *)calloc(1, sizeof(struct printbuf));  | 
42  | 17.6k  |   if (!p)  | 
43  | 0  |     return NULL;  | 
44  | 17.6k  |   p->size = 32;  | 
45  | 17.6k  |   p->bpos = 0;  | 
46  | 17.6k  |   if (!(p->buf = (char *)malloc(p->size)))  | 
47  | 0  |   { | 
48  | 0  |     free(p);  | 
49  | 0  |     return NULL;  | 
50  | 0  |   }  | 
51  | 17.6k  |   p->buf[0] = '\0';  | 
52  | 17.6k  |   return p;  | 
53  | 17.6k  | }  | 
54  |  |  | 
55  |  | /**  | 
56  |  |  * Extend the buffer p so it has a size of at least min_size.  | 
57  |  |  *  | 
58  |  |  * If the current size is large enough, nothing is changed.  | 
59  |  |  *  | 
60  |  |  * If extension failed, errno is set to indicate the error.  | 
61  |  |  *  | 
62  |  |  * Note: this does not check the available space!  The caller  | 
63  |  |  *  is responsible for performing those calculations.  | 
64  |  |  */  | 
65  |  | static int printbuf_extend(struct printbuf *p, int min_size)  | 
66  | 28.5k  | { | 
67  | 28.5k  |   char *t;  | 
68  | 28.5k  |   int new_size;  | 
69  |  |  | 
70  | 28.5k  |   if (p->size >= min_size)  | 
71  | 4.48k  |     return 0;  | 
72  |  |   /* Prevent signed integer overflows with large buffers. */  | 
73  | 24.0k  |   if (min_size > INT_MAX - 8)  | 
74  | 0  |   { | 
75  | 0  |     errno = EFBIG;  | 
76  | 0  |     return -1;  | 
77  | 0  |   }  | 
78  | 24.0k  |   if (p->size > INT_MAX / 2)  | 
79  | 0  |     new_size = min_size + 8;  | 
80  | 24.0k  |   else { | 
81  | 24.0k  |     new_size = p->size * 2;  | 
82  | 24.0k  |     if (new_size < min_size + 8)  | 
83  | 1.01k  |       new_size = min_size + 8;  | 
84  | 24.0k  |   }  | 
85  |  | #ifdef PRINTBUF_DEBUG  | 
86  |  |   MC_DEBUG("printbuf_extend: realloc " | 
87  |  |            "bpos=%d min_size=%d old_size=%d new_size=%d\n",  | 
88  |  |            p->bpos, min_size, p->size, new_size);  | 
89  |  | #endif /* PRINTBUF_DEBUG */  | 
90  | 24.0k  |   if (!(t = (char *)realloc(p->buf, new_size)))  | 
91  | 0  |     return -1;  | 
92  | 24.0k  |   p->size = new_size;  | 
93  | 24.0k  |   p->buf = t;  | 
94  | 24.0k  |   return 0;  | 
95  | 24.0k  | }  | 
96  |  |  | 
97  |  | int printbuf_memappend(struct printbuf *p, const char *buf, int size)  | 
98  | 1.49M  | { | 
99  |  |   /* Prevent signed integer overflows with large buffers. */  | 
100  | 1.49M  |   if (size < 0 || size > INT_MAX - p->bpos - 1)  | 
101  | 0  |   { | 
102  | 0  |     errno = EFBIG;  | 
103  | 0  |     return -1;  | 
104  | 0  |   }  | 
105  | 1.49M  |   if (p->size <= p->bpos + size + 1)  | 
106  | 28.5k  |   { | 
107  | 28.5k  |     if (printbuf_extend(p, p->bpos + size + 1) < 0)  | 
108  | 0  |       return -1;  | 
109  | 28.5k  |   }  | 
110  | 1.49M  |   memcpy(p->buf + p->bpos, buf, size);  | 
111  | 1.49M  |   p->bpos += size;  | 
112  | 1.49M  |   p->buf[p->bpos] = '\0';  | 
113  | 1.49M  |   return size;  | 
114  | 1.49M  | }  | 
115  |  |  | 
116  |  | int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len)  | 
117  | 0  | { | 
118  | 0  |   int size_needed;  | 
119  |  | 
  | 
120  | 0  |   if (offset == -1)  | 
121  | 0  |     offset = pb->bpos;  | 
122  |  |   /* Prevent signed integer overflows with large buffers. */  | 
123  | 0  |   if (len < 0 || offset < -1 || len > INT_MAX - offset)  | 
124  | 0  |   { | 
125  | 0  |     errno = EFBIG;  | 
126  | 0  |     return -1;  | 
127  | 0  |   }  | 
128  | 0  |   size_needed = offset + len;  | 
129  | 0  |   if (pb->size < size_needed)  | 
130  | 0  |   { | 
131  | 0  |     if (printbuf_extend(pb, size_needed) < 0)  | 
132  | 0  |       return -1;  | 
133  | 0  |   }  | 
134  |  |  | 
135  | 0  |   if (pb->bpos < offset)  | 
136  | 0  |     memset(pb->buf + pb->bpos, '\0', offset - pb->bpos);  | 
137  | 0  |   memset(pb->buf + offset, charvalue, len);  | 
138  | 0  |   if (pb->bpos < size_needed)  | 
139  | 0  |     pb->bpos = size_needed;  | 
140  |  | 
  | 
141  | 0  |   return 0;  | 
142  | 0  | }  | 
143  |  |  | 
144  |  | int sprintbuf(struct printbuf *p, const char *msg, ...)  | 
145  | 0  | { | 
146  | 0  |   va_list ap;  | 
147  | 0  |   char *t;  | 
148  | 0  |   int size;  | 
149  | 0  |   char buf[128];  | 
150  |  |  | 
151  |  |   /* use stack buffer first */  | 
152  | 0  |   va_start(ap, msg);  | 
153  | 0  |   size = vsnprintf(buf, 128, msg, ap);  | 
154  | 0  |   va_end(ap);  | 
155  |  |   /* if string is greater than stack buffer, then use dynamic string  | 
156  |  |    * with vasprintf.  Note: some implementations of vsnprintf return -1  | 
157  |  |    * if output is truncated whereas some return the number of bytes that  | 
158  |  |    * would have been written - this code handles both cases.  | 
159  |  |    */  | 
160  | 0  |   if (size < 0 || size > 127)  | 
161  | 0  |   { | 
162  | 0  |     va_start(ap, msg);  | 
163  | 0  |     if ((size = vasprintf(&t, msg, ap)) < 0)  | 
164  | 0  |     { | 
165  | 0  |       va_end(ap);  | 
166  | 0  |       return -1;  | 
167  | 0  |     }  | 
168  | 0  |     va_end(ap);  | 
169  | 0  |     size = printbuf_memappend(p, t, size);  | 
170  | 0  |     free(t);  | 
171  | 0  |   }  | 
172  | 0  |   else  | 
173  | 0  |   { | 
174  | 0  |     size = printbuf_memappend(p, buf, size);  | 
175  | 0  |   }  | 
176  | 0  |   return size;  | 
177  | 0  | }  | 
178  |  |  | 
179  |  | void printbuf_reset(struct printbuf *p)  | 
180  | 450k  | { | 
181  | 450k  |   p->buf[0] = '\0';  | 
182  | 450k  |   p->bpos = 0;  | 
183  | 450k  | }  | 
184  |  |  | 
185  |  | void printbuf_free(struct printbuf *p)  | 
186  | 416k  | { | 
187  | 416k  |   if (p)  | 
188  | 17.6k  |   { | 
189  | 17.6k  |     free(p->buf);  | 
190  | 17.6k  |     free(p);  | 
191  | 17.6k  |   }  | 
192  | 416k  | }  |