| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 1 | /* | 
| Michael Clark | f6a6e48 | 2007-03-13 08:26:23 +0000 | [diff] [blame] | 2 | * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 3 | * | 
| Michael Clark | f6a6e48 | 2007-03-13 08:26:23 +0000 | [diff] [blame] | 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 5 | * Michael Clark <michael@metaparadigm.com> | 
|  | 6 | * | 
| Michael Clark | f6a6e48 | 2007-03-13 08:26:23 +0000 | [diff] [blame] | 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. | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 9 | * | 
| Michael Clark | 95f55a7 | 2009-04-27 08:16:58 +0000 | [diff] [blame] | 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 | * (http://www.opensource.org/licenses/mit-license.php) | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 14 | */ | 
|  | 15 |  | 
| Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 16 | #include "config.h" | 
|  | 17 |  | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 18 | #include <stdio.h> | 
|  | 19 | #include <stdlib.h> | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 20 | #include <string.h> | 
|  | 21 |  | 
| Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 22 | #if HAVE_STDARG_H | 
|  | 23 | # include <stdarg.h> | 
|  | 24 | #else /* !HAVE_STDARG_H */ | 
|  | 25 | # error Not enough var arg support! | 
|  | 26 | #endif /* HAVE_STDARG_H */ | 
|  | 27 |  | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 28 | #include "bits.h" | 
|  | 29 | #include "debug.h" | 
|  | 30 | #include "printbuf.h" | 
|  | 31 |  | 
| Eric Haszlakiewicz | 2d48543 | 2012-04-02 15:39:55 -0500 | [diff] [blame] | 32 | static int printbuf_extend(struct printbuf *p, int min_size); | 
|  | 33 |  | 
| Michael Clark | e8de078 | 2009-02-25 01:45:00 +0000 | [diff] [blame] | 34 | struct printbuf* printbuf_new(void) | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 35 | { | 
|  | 36 | struct printbuf *p; | 
|  | 37 |  | 
| Michael Clark | aaec1ef | 2009-02-25 02:31:32 +0000 | [diff] [blame] | 38 | p = (struct printbuf*)calloc(1, sizeof(struct printbuf)); | 
|  | 39 | if(!p) return NULL; | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 40 | p->size = 32; | 
|  | 41 | p->bpos = 0; | 
| Michael Clark | aaec1ef | 2009-02-25 02:31:32 +0000 | [diff] [blame] | 42 | if(!(p->buf = (char*)malloc(p->size))) { | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 43 | free(p); | 
|  | 44 | return NULL; | 
|  | 45 | } | 
|  | 46 | return p; | 
|  | 47 | } | 
|  | 48 |  | 
|  | 49 |  | 
| Eric Haszlakiewicz | 0d79b53 | 2012-04-03 14:54:25 -0500 | [diff] [blame] | 50 | /** | 
|  | 51 | * Extend the buffer p so it has a size of at least min_size. | 
|  | 52 | * | 
|  | 53 | * If the current size is large enough, nothing is changed. | 
|  | 54 | * | 
|  | 55 | * Note: this does not check the available space!  The caller | 
|  | 56 | *  is responsible for performing those calculations. | 
|  | 57 | */ | 
| Eric Haszlakiewicz | 2d48543 | 2012-04-02 15:39:55 -0500 | [diff] [blame] | 58 | static int printbuf_extend(struct printbuf *p, int min_size) | 
|  | 59 | { | 
|  | 60 | char *t; | 
|  | 61 | int new_size; | 
|  | 62 |  | 
|  | 63 | if (p->size >= min_size) | 
|  | 64 | return 0; | 
|  | 65 |  | 
| Eric Haszlakiewicz | 0d79b53 | 2012-04-03 14:54:25 -0500 | [diff] [blame] | 66 | new_size = json_max(p->size * 2, min_size + 8); | 
| Eric Haszlakiewicz | 2d48543 | 2012-04-02 15:39:55 -0500 | [diff] [blame] | 67 | #ifdef PRINTBUF_DEBUG | 
|  | 68 | MC_DEBUG("printbuf_memappend: realloc " | 
| Eric Haszlakiewicz | 0d79b53 | 2012-04-03 14:54:25 -0500 | [diff] [blame] | 69 | "bpos=%d min_size=%d old_size=%d new_size=%d\n", | 
|  | 70 | p->bpos, min_size, p->size, new_size); | 
| Eric Haszlakiewicz | 2d48543 | 2012-04-02 15:39:55 -0500 | [diff] [blame] | 71 | #endif /* PRINTBUF_DEBUG */ | 
|  | 72 | if(!(t = (char*)realloc(p->buf, new_size))) | 
|  | 73 | return -1; | 
|  | 74 | p->size = new_size; | 
|  | 75 | p->buf = t; | 
|  | 76 | return 0; | 
|  | 77 | } | 
|  | 78 |  | 
| Michael Clark | 68cafad | 2009-01-06 22:56:57 +0000 | [diff] [blame] | 79 | int printbuf_memappend(struct printbuf *p, const char *buf, int size) | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 80 | { | 
| Eric Haszlakiewicz | 0d79b53 | 2012-04-03 14:54:25 -0500 | [diff] [blame] | 81 | if (p->size <= p->bpos + size + 1) { | 
|  | 82 | if (printbuf_extend(p, p->bpos + size + 1) < 0) | 
| Eric Haszlakiewicz | 2d48543 | 2012-04-02 15:39:55 -0500 | [diff] [blame] | 83 | return -1; | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 84 | } | 
|  | 85 | memcpy(p->buf + p->bpos, buf, size); | 
|  | 86 | p->bpos += size; | 
|  | 87 | p->buf[p->bpos]= '\0'; | 
|  | 88 | return size; | 
|  | 89 | } | 
|  | 90 |  | 
| Eric Haszlakiewicz | 2d48543 | 2012-04-02 15:39:55 -0500 | [diff] [blame] | 91 | int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) | 
|  | 92 | { | 
|  | 93 | int size_needed; | 
|  | 94 |  | 
|  | 95 | if (offset == -1) | 
|  | 96 | offset = pb->bpos; | 
|  | 97 | size_needed = offset + len; | 
| Eric Haszlakiewicz | 0d79b53 | 2012-04-03 14:54:25 -0500 | [diff] [blame] | 98 | if (pb->size < size_needed) | 
| Eric Haszlakiewicz | 2d48543 | 2012-04-02 15:39:55 -0500 | [diff] [blame] | 99 | { | 
|  | 100 | if (printbuf_extend(pb, size_needed) < 0) | 
|  | 101 | return -1; | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | memset(pb->buf + offset, charvalue, len); | 
|  | 105 | if (pb->bpos < size_needed) | 
|  | 106 | pb->bpos = size_needed; | 
|  | 107 |  | 
|  | 108 | return 0; | 
|  | 109 | } | 
|  | 110 |  | 
| John Arbash Meinel | 6a231e4 | 2012-02-01 09:27:49 +0100 | [diff] [blame] | 111 | #if !HAVE_VSNPRINTF && defined(_MSC_VER) | 
| Michael Clark | 4504df7 | 2007-03-13 08:26:20 +0000 | [diff] [blame] | 112 | # define vsnprintf _vsnprintf | 
|  | 113 | #elif !HAVE_VSNPRINTF /* !HAVE_VSNPRINTF */ | 
|  | 114 | # error Need vsnprintf! | 
|  | 115 | #endif /* !HAVE_VSNPRINTF && defined(WIN32) */ | 
|  | 116 |  | 
|  | 117 | #if !HAVE_VASPRINTF | 
|  | 118 | /* CAW: compliant version of vasprintf */ | 
|  | 119 | static int vasprintf(char **buf, const char *fmt, va_list ap) | 
|  | 120 | { | 
|  | 121 | #ifndef WIN32 | 
|  | 122 | static char _T_emptybuffer = '\0'; | 
|  | 123 | #endif /* !defined(WIN32) */ | 
|  | 124 | int chars; | 
|  | 125 | char *b; | 
|  | 126 |  | 
|  | 127 | if(!buf) { return -1; } | 
|  | 128 |  | 
|  | 129 | #ifdef WIN32 | 
|  | 130 | chars = _vscprintf(fmt, ap)+1; | 
|  | 131 | #else /* !defined(WIN32) */ | 
|  | 132 | /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite | 
|  | 133 | our buffer like on some 64bit sun systems.... but hey, its time to move on */ | 
|  | 134 | chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1; | 
|  | 135 | if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */ | 
|  | 136 | #endif /* defined(WIN32) */ | 
|  | 137 |  | 
|  | 138 | b = (char*)malloc(sizeof(char)*chars); | 
|  | 139 | if(!b) { return -1; } | 
|  | 140 |  | 
|  | 141 | if((chars = vsprintf(b, fmt, ap)) < 0) | 
|  | 142 | { | 
|  | 143 | free(b); | 
|  | 144 | } else { | 
|  | 145 | *buf = b; | 
|  | 146 | } | 
|  | 147 |  | 
|  | 148 | return chars; | 
|  | 149 | } | 
|  | 150 | #endif /* !HAVE_VASPRINTF */ | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 151 |  | 
|  | 152 | int sprintbuf(struct printbuf *p, const char *msg, ...) | 
|  | 153 | { | 
|  | 154 | va_list ap; | 
|  | 155 | char *t; | 
|  | 156 | int size; | 
|  | 157 | char buf[128]; | 
|  | 158 |  | 
|  | 159 | /* user stack buffer first */ | 
|  | 160 | va_start(ap, msg); | 
|  | 161 | size = vsnprintf(buf, 128, msg, ap); | 
|  | 162 | va_end(ap); | 
|  | 163 | /* if string is greater than stack buffer, then use dynamic string | 
|  | 164 | with vasprintf.  Note: some implementation of vsnprintf return -1 | 
|  | 165 | if output is truncated whereas some return the number of bytes that | 
| Christopher Watford | 543bb14 | 2009-07-08 03:46:10 +0000 | [diff] [blame] | 166 | would have been written - this code handles both cases. */ | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 167 | if(size == -1 || size > 127) { | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 168 | va_start(ap, msg); | 
| ehaszla | 252669c | 2010-12-07 18:15:35 +0000 | [diff] [blame] | 169 | if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; } | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 170 | va_end(ap); | 
| Michael Clark | 95f55a7 | 2009-04-27 08:16:58 +0000 | [diff] [blame] | 171 | printbuf_memappend(p, t, size); | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 172 | free(t); | 
| Michael Clark | 95f55a7 | 2009-04-27 08:16:58 +0000 | [diff] [blame] | 173 | return size; | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 174 | } else { | 
| Michael Clark | 95f55a7 | 2009-04-27 08:16:58 +0000 | [diff] [blame] | 175 | printbuf_memappend(p, buf, size); | 
|  | 176 | return size; | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 177 | } | 
|  | 178 | } | 
|  | 179 |  | 
| Michael Clark | f0d0888 | 2007-03-13 08:26:18 +0000 | [diff] [blame] | 180 | void printbuf_reset(struct printbuf *p) | 
|  | 181 | { | 
|  | 182 | p->buf[0] = '\0'; | 
|  | 183 | p->bpos = 0; | 
|  | 184 | } | 
|  | 185 |  | 
|  | 186 | void printbuf_free(struct printbuf *p) | 
|  | 187 | { | 
|  | 188 | if(p) { | 
|  | 189 | free(p->buf); | 
|  | 190 | free(p); | 
|  | 191 | } | 
|  | 192 | } |