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