Blame dwarfdump/esb.c

Packit cdaae3
/*
Packit cdaae3
  Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
Packit cdaae3
  Portions Copyright (C) 2013-2017 David Anderson. All Rights Reserved.
Packit cdaae3
  This program is free software; you can redistribute it and/or modify it
Packit cdaae3
  under the terms of version 2 of the GNU General Public License as
Packit cdaae3
  published by the Free Software Foundation.
Packit cdaae3
Packit cdaae3
  This program is distributed in the hope that it would be useful, but
Packit cdaae3
  WITHOUT ANY WARRANTY; without even the implied warranty of
Packit cdaae3
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Packit cdaae3
Packit cdaae3
  Further, this software is distributed without any warranty that it is
Packit cdaae3
  free of the rightful claim of any third person regarding infringement
Packit cdaae3
  or the like.  Any license provided herein, whether implied or
Packit cdaae3
  otherwise, applies only to this software file.  Patent licenses, if
Packit cdaae3
  any, provided herein do not apply to combinations of this program with
Packit cdaae3
  other software, or any other product whatsoever.
Packit cdaae3
Packit cdaae3
  You should have received a copy of the GNU General Public License along
Packit cdaae3
  with this program; if not, write the Free Software Foundation, Inc., 51
Packit cdaae3
  Franklin Street - Fifth Floor, Boston MA 02110-1301, USA.
Packit cdaae3
*/
Packit cdaae3
Packit cdaae3
/*  esb.c
Packit cdaae3
    extensible string buffer.
Packit cdaae3
Packit cdaae3
    A simple means (vaguely like a C++ class) that
Packit cdaae3
    enables safely saving strings of arbitrary length built up
Packit cdaae3
    in small pieces.
Packit cdaae3
Packit cdaae3
    We really do allow only C strings here. NUL bytes
Packit cdaae3
    in a string result in adding only up to the NUL (and
Packit cdaae3
    in the case of certain interfaces here a warning
Packit cdaae3
    to stderr).
Packit cdaae3
Packit cdaae3
    Do selftest as follows:
Packit cdaae3
        gcc -DSELFTEST esb.c
Packit cdaae3
        ./a.out
Packit cdaae3
        valgrind --leak-check=full ./a.out
Packit cdaae3
Packit cdaae3
    The functions assume that
Packit cdaae3
    pointer arguments of all kinds are not NULL.
Packit cdaae3
*/
Packit cdaae3
Packit cdaae3
#ifndef SELFTEST
Packit cdaae3
#include "globals.h"
Packit cdaae3
#else
Packit cdaae3
#include <stdio.h> /* SELFTEST */
Packit cdaae3
#include <string.h> /* SELFTEST */
Packit cdaae3
#include <stdlib.h> /* SELFTEST */
Packit cdaae3
typedef char * string; /* SELFTEST */
Packit cdaae3
#include <stdarg.h>   /* For va_start va_arg va_list */
Packit cdaae3
#endif
Packit cdaae3
#include "esb.h"
Packit cdaae3
Packit cdaae3
/*  INITIAL_ALLOC value takes no account of space for a trailing NUL,
Packit cdaae3
    the NUL is accounted for in init_esb_string
Packit cdaae3
    and in later tests against esb_allocated_size. */
Packit cdaae3
#ifdef SELFTEST
Packit cdaae3
#define INITIAL_ALLOC 1  /* SELFTEST */
Packit cdaae3
#else
Packit cdaae3
/*  There is nothing magic about this size.
Packit cdaae3
    It is just big enough to avoid most resizing. */
Packit cdaae3
#define INITIAL_ALLOC 16
Packit cdaae3
#endif
Packit cdaae3
/*  Allow for final NUL */
Packit cdaae3
static size_t alloc_size = INITIAL_ALLOC;
Packit cdaae3
Packit cdaae3
/* NULL device used when printing formatted strings */
Packit cdaae3
static FILE *null_device_handle = 0;
Packit cdaae3
#if _WIN32
Packit cdaae3
#define NULL_DEVICE_NAME "NUL"
Packit cdaae3
#else
Packit cdaae3
#define NULL_DEVICE_NAME "/dev/null"
Packit cdaae3
#endif /* _WIN32 */
Packit cdaae3
Packit cdaae3
/* Open the null device used during formatting printing */
Packit cdaae3
FILE *esb_open_null_device(void)
Packit cdaae3
{
Packit cdaae3
    if (!null_device_handle) {
Packit cdaae3
        null_device_handle = fopen(NULL_DEVICE_NAME,"w");
Packit cdaae3
    }
Packit cdaae3
    return null_device_handle;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/* Close the null device used during formatting printing */
Packit cdaae3
void esb_close_null_device(void)
Packit cdaae3
{
Packit cdaae3
    if (null_device_handle) {
Packit cdaae3
        fclose(null_device_handle);
Packit cdaae3
    }
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static void
Packit cdaae3
init_esb_string(struct esb_s *data, size_t min_len)
Packit cdaae3
{
Packit cdaae3
    char* d;
Packit cdaae3
Packit cdaae3
    if (data->esb_allocated_size > 0) {
Packit cdaae3
        return;
Packit cdaae3
    }
Packit cdaae3
    /* Only esb_constructor applied. Allow for string space. */
Packit cdaae3
    if (min_len <= alloc_size) {
Packit cdaae3
        min_len = alloc_size +1;/* Allow for NUL at end */
Packit cdaae3
    } else  {
Packit cdaae3
        min_len++ ; /* Allow for NUL at end */
Packit cdaae3
    }
Packit cdaae3
    d = malloc(min_len);
Packit cdaae3
    if (!d) {
Packit cdaae3
        fprintf(stderr,
Packit cdaae3
            "dwarfdump is out of memory allocating %lu bytes\n",
Packit cdaae3
            (unsigned long) min_len);
Packit cdaae3
        exit(5);
Packit cdaae3
    }
Packit cdaae3
    data->esb_string = d;
Packit cdaae3
    data->esb_allocated_size = min_len;
Packit cdaae3
    data->esb_string[0] = 0;
Packit cdaae3
    data->esb_used_bytes = 0;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/*  Make more room. Leaving  contents unchanged, effectively.
Packit cdaae3
    The NUL byte at end has room and this preserves that room.
Packit cdaae3
*/
Packit cdaae3
static void
Packit cdaae3
esb_allocate_more(struct esb_s *data, size_t len)
Packit cdaae3
{
Packit cdaae3
    size_t new_size = data->esb_allocated_size + len;
Packit cdaae3
    char* newd = 0;
Packit cdaae3
Packit cdaae3
    if (new_size < alloc_size) {
Packit cdaae3
        new_size = alloc_size;
Packit cdaae3
    }
Packit cdaae3
    newd = realloc(data->esb_string, new_size);
Packit cdaae3
    if (!newd) {
Packit cdaae3
        fprintf(stderr, "dwarfdump is out of memory re-allocating "
Packit cdaae3
            "%lu bytes\n", (unsigned long) new_size);
Packit cdaae3
        exit(5);
Packit cdaae3
    }
Packit cdaae3
    /*  If the area was reallocated by realloc() the earlier
Packit cdaae3
        space was free()d by realloc(). */
Packit cdaae3
    data->esb_string = newd;
Packit cdaae3
    data->esb_allocated_size = new_size;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/*  Ensure that the total buffer length is large enough that
Packit cdaae3
    at least minlen bytes are available, unused,
Packit cdaae3
    in the allocation. */
Packit cdaae3
void
Packit cdaae3
esb_force_allocation(struct esb_s *data, size_t minlen)
Packit cdaae3
{
Packit cdaae3
    if (data->esb_allocated_size < (data->esb_used_bytes + minlen)) {
Packit cdaae3
        esb_allocate_more(data,minlen);
Packit cdaae3
    }
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static void
Packit cdaae3
esb_appendn_internal(struct esb_s *data, const char * in_string, size_t len);
Packit cdaae3
Packit cdaae3
void
Packit cdaae3
esb_appendn(struct esb_s *data, const char * in_string, size_t len)
Packit cdaae3
{
Packit cdaae3
    size_t full_len = strlen(in_string);
Packit cdaae3
Packit cdaae3
    if (full_len < len) {
Packit cdaae3
        fprintf(stderr, "dwarfdump esb internal error, bad string length "
Packit cdaae3
            " %lu  < %lu \n",
Packit cdaae3
            (unsigned long) full_len, (unsigned long) len);
Packit cdaae3
        len = full_len;
Packit cdaae3
    }
Packit cdaae3
Packit cdaae3
    esb_appendn_internal(data, in_string, len);
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/*  The length is gotten from the in_string itself. */
Packit cdaae3
void
Packit cdaae3
esb_append(struct esb_s *data, const char * in_string)
Packit cdaae3
{
Packit cdaae3
    size_t len = 0;
Packit cdaae3
    if(in_string) {
Packit cdaae3
        len = strlen(in_string);
Packit cdaae3
        if (len) {
Packit cdaae3
            esb_appendn_internal(data, in_string, len);
Packit cdaae3
        }
Packit cdaae3
    }
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/*  The 'len' is believed. Do not pass in strings < len bytes long. */
Packit cdaae3
static void
Packit cdaae3
esb_appendn_internal(struct esb_s *data, const char * in_string, size_t len)
Packit cdaae3
{
Packit cdaae3
    size_t remaining = 0;
Packit cdaae3
    size_t needed = len;
Packit cdaae3
Packit cdaae3
    if (data->esb_allocated_size == 0) {
Packit cdaae3
        size_t maxlen = (len >= alloc_size)? (len):alloc_size;
Packit cdaae3
Packit cdaae3
        init_esb_string(data, maxlen);
Packit cdaae3
    }
Packit cdaae3
    /*  ASSERT: data->esb_allocated_size > data->esb_used_bytes  */
Packit cdaae3
    remaining = data->esb_allocated_size - data->esb_used_bytes;
Packit cdaae3
    if (remaining <= needed) {
Packit cdaae3
        esb_allocate_more(data,len);
Packit cdaae3
    }
Packit cdaae3
    strncpy(&data->esb_string[data->esb_used_bytes], in_string, len);
Packit cdaae3
    data->esb_used_bytes += len;
Packit cdaae3
    /* Insist on explicit NUL terminator */
Packit cdaae3
    data->esb_string[data->esb_used_bytes] = 0;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/*  Always returns an empty string or a non-empty string. Never 0. */
Packit cdaae3
char*
Packit cdaae3
esb_get_string(struct esb_s *data)
Packit cdaae3
{
Packit cdaae3
    if (data->esb_allocated_size == 0) {
Packit cdaae3
        init_esb_string(data, alloc_size);
Packit cdaae3
    }
Packit cdaae3
    return data->esb_string;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
Packit cdaae3
/*  Sets esb_used_bytes to zero. The string is not freed and
Packit cdaae3
    esb_allocated_size is unchanged.  */
Packit cdaae3
void
Packit cdaae3
esb_empty_string(struct esb_s *data)
Packit cdaae3
{
Packit cdaae3
    if (data->esb_allocated_size == 0) {
Packit cdaae3
        init_esb_string(data, alloc_size);
Packit cdaae3
    }
Packit cdaae3
    data->esb_used_bytes = 0;
Packit cdaae3
    data->esb_string[0] = 0;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
Packit cdaae3
/*  Return esb_used_bytes. */
Packit cdaae3
size_t
Packit cdaae3
esb_string_len(struct esb_s *data)
Packit cdaae3
{
Packit cdaae3
    return data->esb_used_bytes;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/*  *data is presumed to contain garbage, not values, and
Packit cdaae3
    is properly initialized here. */
Packit cdaae3
void
Packit cdaae3
esb_constructor(struct esb_s *data)
Packit cdaae3
{
Packit cdaae3
    memset(data, 0, sizeof(*data));
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/*  The string is freed, contents of *data set to zeroes. */
Packit cdaae3
void
Packit cdaae3
esb_destructor(struct esb_s *data)
Packit cdaae3
{
Packit cdaae3
    if (data->esb_string) {
Packit cdaae3
        free(data->esb_string);
Packit cdaae3
        data->esb_string = 0;
Packit cdaae3
    }
Packit cdaae3
    esb_constructor(data);
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
Packit cdaae3
/*  To get all paths in the code tested, this sets the
Packit cdaae3
    allocation/reallocation to the given value, which can be quite small
Packit cdaae3
    but must not be zero. */
Packit cdaae3
void
Packit cdaae3
esb_alloc_size(size_t size)
Packit cdaae3
{
Packit cdaae3
    alloc_size = size;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
size_t
Packit cdaae3
esb_get_allocated_size(struct esb_s *data)
Packit cdaae3
{
Packit cdaae3
    return data->esb_allocated_size;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/*  Make more room. Leaving  contents unchanged, effectively.
Packit cdaae3
    The NUL byte at end has room and this preserves that room.
Packit cdaae3
*/
Packit cdaae3
static void
Packit cdaae3
esb_allocate_more_if_needed(struct esb_s *data,
Packit cdaae3
    const char *in_string,va_list ap)
Packit cdaae3
{
Packit cdaae3
#ifndef _WIN32
Packit cdaae3
    static char a_buffer[512];
Packit cdaae3
#endif /* _WIN32*/
Packit cdaae3
Packit cdaae3
    int netlen = 0;
Packit cdaae3
    va_list ap_copy;
Packit cdaae3
Packit cdaae3
    /* Preserve the original argument list, to be used a second time */
Packit cdaae3
    va_copy(ap_copy,ap);
Packit cdaae3
Packit cdaae3
#ifdef _WIN32
Packit cdaae3
    netlen = vfprintf(null_device_handle,in_string,ap_copy);
Packit cdaae3
#else
Packit cdaae3
    netlen = vsnprintf(a_buffer,sizeof(a_buffer),in_string,ap_copy);
Packit cdaae3
#endif /* _WIN32*/
Packit cdaae3
Packit cdaae3
    /*  "The object ap may be passed as an argument to another
Packit cdaae3
        function; if that function invokes the va_arg()
Packit cdaae3
        macro with parameter ap, the value of ap in the calling
Packit cdaae3
        function is unspecified and shall be passed to the va_end()
Packit cdaae3
        macro prior to any further reference to ap."
Packit cdaae3
        Single Unix Specification. */
Packit cdaae3
    va_end(ap_copy);
Packit cdaae3
Packit cdaae3
    /* Allocate enough space to hold the full text */
Packit cdaae3
    esb_force_allocation(data,netlen + 1);
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/*  Append a formatted string */
Packit cdaae3
void
Packit cdaae3
esb_append_printf_ap(struct esb_s *data,const char *in_string,va_list ap)
Packit cdaae3
{
Packit cdaae3
    int netlen = 0;
Packit cdaae3
    int expandedlen = 0;
Packit cdaae3
Packit cdaae3
    /* Allocate enough space for the input string */
Packit cdaae3
    esb_allocate_more_if_needed(data,in_string,ap);
Packit cdaae3
Packit cdaae3
    netlen = data->esb_allocated_size - data->esb_used_bytes;
Packit cdaae3
    expandedlen =
Packit cdaae3
        vsnprintf(&data->esb_string[data->esb_used_bytes],
Packit cdaae3
        netlen,in_string,ap);
Packit cdaae3
    if (expandedlen < 0) {
Packit cdaae3
        /*  There was an error.
Packit cdaae3
            Do nothing. */
Packit cdaae3
        return;
Packit cdaae3
    }
Packit cdaae3
    if (netlen < expandedlen) {
Packit cdaae3
        /*  If data was too small, the max written was one less than
Packit cdaae3
            netlen. */
Packit cdaae3
        data->esb_used_bytes += netlen - 1;
Packit cdaae3
    } else {
Packit cdaae3
        data->esb_used_bytes += expandedlen;
Packit cdaae3
    }
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/*  Append a formatted string */
Packit cdaae3
void
Packit cdaae3
esb_append_printf(struct esb_s *data,const char *in_string, ...)
Packit cdaae3
{
Packit cdaae3
    va_list ap;
Packit cdaae3
    va_start(ap,in_string);
Packit cdaae3
    esb_append_printf_ap(data,in_string,ap);
Packit cdaae3
    /*  "The object ap may be passed as an argument to another
Packit cdaae3
        function; if that function invokes the va_arg()
Packit cdaae3
        macro with parameter ap, the value of ap in the calling
Packit cdaae3
        function is unspecified and shall be passed to the va_end()
Packit cdaae3
        macro prior to any further reference to ap."
Packit cdaae3
        Single Unix Specification. */
Packit cdaae3
    va_end(ap);
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
/*  Get a copy of the internal data buffer.
Packit cdaae3
    It is up to the code calling this
Packit cdaae3
    to free() the string using the
Packit cdaae3
    pointer returned here. */
Packit cdaae3
char*
Packit cdaae3
esb_get_copy(struct esb_s *data)
Packit cdaae3
{
Packit cdaae3
    char* copy = NULL;
Packit cdaae3
    size_t len = esb_string_len(data);
Packit cdaae3
    if (len) {
Packit cdaae3
        copy = (char*)malloc(len + 1);
Packit cdaae3
        strcpy(copy,esb_get_string(data));
Packit cdaae3
    }
Packit cdaae3
    return copy;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
Packit cdaae3
#ifdef SELFTEST
Packit cdaae3
static int failcount = 0;
Packit cdaae3
void
Packit cdaae3
validate_esb(int instance,
Packit cdaae3
   struct esb_s* d,
Packit cdaae3
   size_t explen,
Packit cdaae3
   size_t expalloc,
Packit cdaae3
   const char *expout)
Packit cdaae3
{
Packit cdaae3
    printf("  TEST instance %d\n",instance);
Packit cdaae3
    if (esb_string_len(d) != explen) {
Packit cdaae3
        ++failcount;
Packit cdaae3
        printf("  FAIL instance %d  esb_string_len() %u explen %u\n",
Packit cdaae3
            instance,(unsigned)esb_string_len(d),(unsigned)explen);
Packit cdaae3
    }
Packit cdaae3
    if (d->esb_allocated_size != expalloc) {
Packit cdaae3
        ++failcount;
Packit cdaae3
        printf("  FAIL instance %d  esb_allocated_size  %u expalloc %u\n",
Packit cdaae3
            instance,(unsigned)d->esb_allocated_size,(unsigned)expalloc);
Packit cdaae3
    }
Packit cdaae3
    if(strcmp(esb_get_string(d),expout)) {
Packit cdaae3
        ++failcount;
Packit cdaae3
        printf("  FAIL instance %d esb_get_stringr %s expstr %s\n",
Packit cdaae3
            instance,esb_get_string(d),expout);
Packit cdaae3
    }
Packit cdaae3
}
Packit cdaae3
void
Packit cdaae3
trialprint_1(struct esb_s *d, char *format,...)
Packit cdaae3
{
Packit cdaae3
    va_list ap;
Packit cdaae3
Packit cdaae3
    va_start(ap,format);
Packit cdaae3
    esb_append_printf_ap(d,format,ap);
Packit cdaae3
    va_end(ap);
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
void
Packit cdaae3
trialprint(struct esb_s *d)
Packit cdaae3
{
Packit cdaae3
    const char * s = "insert me";
Packit cdaae3
    trialprint_1(d,"aaaa %s bbbb",s);
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
Packit cdaae3
int main()
Packit cdaae3
{
Packit cdaae3
#ifdef _WIN32
Packit cdaae3
    /* Open the null device used during formatting printing */
Packit cdaae3
    if (!esb_open_null_device())
Packit cdaae3
    {
Packit cdaae3
        fprintf(stderr, "esb: Unable to open null device.\n");
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
#endif /* _WIN32 */
Packit cdaae3
Packit cdaae3
   {
Packit cdaae3
        struct esb_s d;
Packit cdaae3
        esb_constructor(&d);
Packit cdaae3
        esb_append(&d,"a");
Packit cdaae3
        validate_esb(1,&d,1,2,"a");
Packit cdaae3
        esb_append(&d,"b");
Packit cdaae3
        validate_esb(2,&d,2,3,"ab");
Packit cdaae3
        esb_append(&d,"c");
Packit cdaae3
        validate_esb(3,&d,3,4,"abc");
Packit cdaae3
        esb_empty_string(&d);
Packit cdaae3
        validate_esb(4,&d,0,4,"");
Packit cdaae3
        esb_destructor(&d);
Packit cdaae3
    }
Packit cdaae3
    {
Packit cdaae3
        struct esb_s d;
Packit cdaae3
        esb_constructor(&d);
Packit cdaae3
        esb_append(&d,"aa");
Packit cdaae3
        validate_esb(6,&d,2,3,"aa");
Packit cdaae3
        esb_append(&d,"bbb");
Packit cdaae3
        validate_esb(7,&d,5,6,"aabbb");
Packit cdaae3
        esb_append(&d,"c");
Packit cdaae3
        validate_esb(8,&d,6,7,"aabbbc");
Packit cdaae3
        esb_empty_string(&d);
Packit cdaae3
        validate_esb(9,&d,0,7,"");
Packit cdaae3
        esb_destructor(&d);
Packit cdaae3
    }
Packit cdaae3
    {
Packit cdaae3
        struct esb_s d;
Packit cdaae3
        static char oddarray[7] = {'a','b',0,'c','c','d',0};
Packit cdaae3
        esb_constructor(&d);
Packit cdaae3
        fprintf(stderr,"  esb_appendn call error(intentional). Expect msg on stderr\n");
Packit cdaae3
        /* This provokes a msg on stderr. Bad input. */
Packit cdaae3
        esb_appendn(&d,oddarray,6);
Packit cdaae3
        validate_esb(10,&d,2,3,"ab");
Packit cdaae3
        esb_appendn(&d,"cc",1);
Packit cdaae3
        validate_esb(11,&d,3,4,"abc");
Packit cdaae3
        esb_empty_string(&d);
Packit cdaae3
        validate_esb(12,&d,0,4,"");
Packit cdaae3
        esb_destructor(&d);
Packit cdaae3
    }
Packit cdaae3
    {
Packit cdaae3
        struct esb_s d;
Packit cdaae3
        esb_constructor(&d);
Packit cdaae3
Packit cdaae3
        esb_force_allocation(&d,7);
Packit cdaae3
        esb_append(&d,"aaaa i");
Packit cdaae3
        validate_esb(13,&d,6,7,"aaaa i");
Packit cdaae3
        esb_destructor(&d);
Packit cdaae3
    }
Packit cdaae3
    {
Packit cdaae3
        struct esb_s d5;
Packit cdaae3
        esb_constructor(&d5;;
Packit cdaae3
Packit cdaae3
        esb_force_allocation(&d5,50);
Packit cdaae3
        trialprint(&d5;;
Packit cdaae3
        validate_esb(14,&d5,19,50,"aaaa insert me bbbb");
Packit cdaae3
        esb_destructor(&d5;;
Packit cdaae3
    }
Packit cdaae3
    {
Packit cdaae3
        struct esb_s d;
Packit cdaae3
        struct esb_s e;
Packit cdaae3
        char* result = NULL;
Packit cdaae3
        esb_constructor(&d);
Packit cdaae3
        esb_constructor(&e);
Packit cdaae3
Packit cdaae3
        esb_append(&d,"abcde fghij klmno pqrst");
Packit cdaae3
        validate_esb(15,&d,23,24,"abcde fghij klmno pqrst");
Packit cdaae3
Packit cdaae3
        result = esb_get_copy(&d);
Packit cdaae3
        esb_append(&e,result);
Packit cdaae3
        validate_esb(16,&e,23,24,"abcde fghij klmno pqrst");
Packit cdaae3
        esb_destructor(&d);
Packit cdaae3
        esb_destructor(&e);
Packit cdaae3
    }
Packit cdaae3
#ifdef _WIN32
Packit cdaae3
    /* Close the null device used during formatting printing */
Packit cdaae3
    esb_close_null_device();
Packit cdaae3
#endif /* _WIN32 */
Packit cdaae3
    if (failcount) {
Packit cdaae3
        printf("FAIL esb test\n");
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
    printf("PASS esb test\n");
Packit cdaae3
    exit(0);
Packit cdaae3
}
Packit cdaae3
#endif /* SELFTEST */