kicad/markdown2html/md_parser/buffer.c

232 lines
4.9 KiB
C

/*
* Copyright (c) 2008, Natacha Porté
* Copyright (c) 2011, Vicent Martí
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define BUFFER_MAX_ALLOC_SIZE (1024 * 1024 * 16) // 16mb
#include "buffer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* MSVC compat */
#if defined(_MSC_VER)
# define _buf_vsnprintf _vsnprintf
#else
# define _buf_vsnprintf vsnprintf
#endif
int bufprefix( const struct buf* buf, const char* prefix )
{
size_t i;
assert( buf && buf->unit );
for( i = 0; i < buf->size; ++i )
{
if( prefix[i] == 0 )
return 0;
if( buf->data[i] != prefix[i] )
return buf->data[i] - prefix[i];
}
return 0;
}
/* bufgrow: increasing the allocated size to the given value */
int bufgrow( struct buf* buf, size_t neosz )
{
size_t neoasz;
void* neodata;
assert( buf && buf->unit );
if( neosz > BUFFER_MAX_ALLOC_SIZE )
return BUF_ENOMEM;
if( buf->asize >= neosz )
return BUF_OK;
neoasz = buf->asize + buf->unit;
while( neoasz < neosz )
neoasz += buf->unit;
neodata = realloc( buf->data, neoasz );
if( !neodata )
return BUF_ENOMEM;
buf->data = neodata;
buf->asize = neoasz;
return BUF_OK;
}
/* bufnew: allocation of a new buffer */
struct buf* bufnew( size_t unit )
{
struct buf* ret;
ret = malloc( sizeof(struct buf) );
if( ret )
{
ret->data = 0;
ret->size = ret->asize = 0;
ret->unit = unit;
}
return ret;
}
/* bufnullterm: NULL-termination of the string array */
const char* bufcstr( struct buf* buf )
{
assert( buf && buf->unit );
if( buf->size < buf->asize && buf->data[buf->size] == 0 )
return (char*) buf->data;
if( buf->size + 1 <= buf->asize || bufgrow( buf, buf->size + 1 ) == 0 )
{
buf->data[buf->size] = 0;
return (char*) buf->data;
}
return NULL;
}
/* bufprintf: formatted printing to a buffer */
void bufprintf( struct buf* buf, const char* fmt, ... )
{
va_list ap;
int n;
assert( buf && buf->unit );
if( buf->size >= buf->asize && bufgrow( buf, buf->size + 1 ) < 0 )
return;
va_start( ap, fmt );
n = _buf_vsnprintf( (char*) buf->data + buf->size, buf->asize - buf->size, fmt, ap );
va_end( ap );
if( n < 0 )
{
#ifdef _MSC_VER
va_start( ap, fmt );
n = _vscprintf( fmt, ap );
va_end( ap );
#else
return;
#endif
}
if( (size_t) n >= buf->asize - buf->size )
{
if( bufgrow( buf, buf->size + n + 1 ) < 0 )
return;
va_start( ap, fmt );
n = _buf_vsnprintf( (char*) buf->data + buf->size, buf->asize - buf->size, fmt, ap );
va_end( ap );
}
if( n < 0 )
return;
buf->size += n;
}
/* bufput: appends raw data to a buffer */
void bufput( struct buf* buf, const void* data, size_t len )
{
assert( buf && buf->unit );
if( buf->size + len > buf->asize && bufgrow( buf, buf->size + len ) < 0 )
return;
memcpy( buf->data + buf->size, data, len );
buf->size += len;
}
/* bufputs: appends a NUL-terminated string to a buffer */
void bufputs( struct buf* buf, const char* str )
{
bufput( buf, str, strlen( str ) );
}
/* bufputc: appends a single uint8_t to a buffer */
void bufputc( struct buf* buf, int c )
{
assert( buf && buf->unit );
if( buf->size + 1 > buf->asize && bufgrow( buf, buf->size + 1 ) < 0 )
return;
buf->data[buf->size] = c;
buf->size += 1;
}
/* bufrelease: decrease the reference count and free the buffer if needed */
void bufrelease( struct buf* buf )
{
if( !buf )
return;
free( buf->data );
free( buf );
}
/* bufreset: frees internal data of the buffer */
void bufreset( struct buf* buf )
{
if( !buf )
return;
free( buf->data );
buf->data = NULL;
buf->size = buf->asize = 0;
}
/* bufslurp: removes a given number of bytes from the head of the array */
void bufslurp( struct buf* buf, size_t len )
{
assert( buf && buf->unit );
if( len >= buf->size )
{
buf->size = 0;
return;
}
buf->size -= len;
memmove( buf->data, buf->data + len, buf->size );
}