committed by
Holger Vogt
8 changed files with 938 additions and 594 deletions
-
64src/frontend/diff.c
-
10src/frontend/numparam/general.h
-
60src/frontend/numparam/mystring.c
-
49src/frontend/numparam/spicenum.c
-
155src/frontend/numparam/xpressn.c
-
74src/frontend/vectors.c
-
286src/include/ngspice/dstring.h
-
834src/misc/dstring.c
@ -1,40 +1,250 @@ |
|||
/* dstring.h */ |
|||
|
|||
#ifndef ngspice_DSTRING_H |
|||
#define ngspice_DSTRING_H |
|||
|
|||
/* ----------------------------------------------------------------- |
|||
* This structure is modified from Tcl. We do this to avoid a |
|||
* conflict and later add a conditional compile to just use the Tcl |
|||
* code if desired. |
|||
----------------------------------------------------------------- */ |
|||
#define SPICE_DSTRING_STATIC_SIZE 200 |
|||
typedef struct spice_dstring { |
|||
char *string; /* Points to beginning of string: either |
|||
* staticSpace below or a malloced array. */ |
|||
int length ; /* Number of characters in the string excluding the |
|||
* terminating NULL. */ |
|||
int spaceAvl ; /* Total number of bytes available for the |
|||
* string and its terminating NULL char. */ |
|||
char staticSpace[SPICE_DSTRING_STATIC_SIZE] ; |
|||
/* Space to use in common case where string |
|||
* is small. */ |
|||
} SPICE_DSTRING, *SPICE_DSTRINGPTR ; |
|||
|
|||
/* ----------------------------------------------------------------- |
|||
* spice_dstring_xxxx routines. Used to manipulate dynamic strings. |
|||
----------------------------------------------------------------- */ |
|||
extern void spice_dstring_init(SPICE_DSTRINGPTR dsPtr) ; |
|||
extern char *spice_dstring_append(SPICE_DSTRINGPTR dsPtr,const char *string,int length) ; |
|||
extern char *spice_dstring_append_lower(SPICE_DSTRINGPTR dsPtr,const char *string,int length) ; |
|||
extern char *spice_dstring_append_char(SPICE_DSTRINGPTR dsPtr,char c) ; |
|||
extern char *spice_dstring_print(SPICE_DSTRINGPTR dsPtr,const char *format, ... ) ; |
|||
extern char *spice_dstring_setlength(SPICE_DSTRINGPTR dsPtr,int length) ; |
|||
extern char *_spice_dstring_setlength(SPICE_DSTRINGPTR dsPtr,int length) ; |
|||
extern void spice_dstring_free(SPICE_DSTRINGPTR dsPtr) ; |
|||
#define spice_dstring_reinit(x_xz) spice_dstring_setlength(x_xz,0) ; |
|||
#define spice_dstring_value(x_xz) ((x_xz)->string) |
|||
#define spice_dstring_space(x_xz) ((x_xz)->spaceAvl) |
|||
#define spice_dstring_length(x_xz) ((x_xz)->length) |
|||
|
|||
#endif |
|||
#ifndef DSTRING_H |
|||
#define DSTRING_H |
|||
|
|||
|
|||
#include <stdarg.h> |
|||
#include <stddef.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
/* Error codes */ |
|||
#define DS_E_OK 0 |
|||
#define DS_E_INVALID (-1) |
|||
#define DS_E_NO_MEMORY (-2) |
|||
|
|||
/* Macros to create and initialize the most common type of dstring, which is |
|||
* one that uses the stack for the initial buffer and begins empty. |
|||
* |
|||
* Example: |
|||
* |
|||
* DS_CREATE(ds1, 50); // Creates dstring ds1 backed by 50 bytes of stack |
|||
* // memory and initialized to "". |
|||
* Note that each DS_CREATE macro must be on a separate line due to the use |
|||
* of the __LINE__ macro. Using __COUNTER__ in its place would resolve this |
|||
* issue, but __COUNTER__ is not part of the ANSI standard. |
|||
*/ |
|||
#undef DS_CONCAT |
|||
#undef DS_CONCAT2 |
|||
#define DS_CONCAT2(a, b) a##b |
|||
#define DS_CONCAT(a, b) DS_CONCAT2(a, b) |
|||
#define DS_CREATE(ds_name, n) \ |
|||
char DS_CONCAT(ds_buf___, __LINE__)[n]; \ |
|||
DSTRING ds_name; \ |
|||
ds_init(&ds_name, DS_CONCAT(ds_buf___, __LINE__), 0,\ |
|||
sizeof DS_CONCAT(ds_buf___, __LINE__), ds_buf_type_stack) |
|||
|
|||
|
|||
/* Structure for maintaining a dynamic string */ |
|||
typedef struct Dstring { |
|||
char *p_buf; /* Active data buffer */ |
|||
size_t length; /* Number of characters in the string excluding the |
|||
* terminating NULL. */ |
|||
size_t n_byte_alloc; /* Allocated size of current buffer */ |
|||
char *p_stack_buf; /* address of stack-based buffer backing dstring |
|||
* or NULL if none */ |
|||
size_t n_byte_stack_buf; /* size of stack_buffer or 0 if none */ |
|||
} DSTRING, *DSTRINGPTR; |
|||
|
|||
|
|||
/* Enumeration defining buffer types used during initialization */ |
|||
typedef enum ds_buf_type { |
|||
ds_buf_type_stack, /* Buffer allocated from stack */ |
|||
ds_buf_type_heap /* Buffer allocated from heap */ |
|||
} ds_buf_type_t; |
|||
|
|||
/* Enumeration defining case conversion */ |
|||
typedef enum ds_case { |
|||
ds_case_as_is, /* Leave characters as they are */ |
|||
ds_case_lower, /* Losercase chars */ |
|||
ds_case_upper /* Uppercase chars */ |
|||
} ds_case_t; |
|||
|
|||
|
|||
|
|||
/* General initialization */ |
|||
int ds_init(DSTRING *p_ds, char *p_buf, size_t length_string, |
|||
size_t n_byte_buf, ds_buf_type_t type_buffer); |
|||
|
|||
/* Free all memory used */ |
|||
void ds_free(DSTRING *p_ds); |
|||
|
|||
|
|||
/* Concatenate string */ |
|||
int ds_cat_str_case(DSTRING *p_ds, const char *sz, ds_case_t case_type); |
|||
inline int ds_cat_str(DSTRING *p_ds, const char *sz) |
|||
{ |
|||
return ds_cat_str_case(p_ds, sz, ds_case_as_is); |
|||
} /* end of function ds_cat_str */ |
|||
|
|||
|
|||
|
|||
/* Concatenate character */ |
|||
int ds_cat_char_case(DSTRING *p_ds, char c, ds_case_t case_type); |
|||
inline int ds_cat_char(DSTRING *p_ds, char c) |
|||
{ |
|||
return ds_cat_char_case(p_ds, c, ds_case_as_is); |
|||
} /* end of function ds_cat_char */ |
|||
|
|||
|
|||
|
|||
/* Concatenate another dstring */ |
|||
int ds_cat_ds_case(DSTRING *p_ds_dst, const DSTRING *p_ds_src, |
|||
ds_case_t case_type); |
|||
inline int ds_cat_ds(DSTRING *p_ds_dst, const DSTRING *p_ds_src) |
|||
{ |
|||
return ds_cat_ds_case(p_ds_dst, p_ds_src, ds_case_as_is); |
|||
} /* end of function ds_cat_ds */ |
|||
|
|||
|
|||
|
|||
/* General concatenation of a memory buffer */ |
|||
int ds_cat_mem_case(DSTRING *p_ds, const char *p_src, size_t n_char, |
|||
ds_case_t type_case); |
|||
inline int ds_cat_mem(DSTRING *p_ds, const char *p_src, size_t n_char) |
|||
{ |
|||
return ds_cat_mem_case(p_ds, p_src, n_char, ds_case_as_is); |
|||
} /* end of function ds_cat_mem */ |
|||
|
|||
|
|||
|
|||
/* Ensure minimum internal buffer size */ |
|||
int ds_reserve(DSTRING *p_ds, size_t n_byte_alloc_min); |
|||
|
|||
/* Concatenate the result of a printf-style format */ |
|||
int ds_cat_printf(DSTRING *p_ds, const char *sz_fmt, ...); |
|||
|
|||
/* Concatenate the result of a printf-style format using va_list */ |
|||
int ds_cat_vprintf(DSTRING *p_ds, const char *sz_fmt, va_list p_arg); |
|||
|
|||
/* Reallocate/free to eliminate unused buffer space */ |
|||
int ds_compact(DSTRING *p_ds); |
|||
|
|||
|
|||
|
|||
/* This function sets the length of the buffer to some size less than |
|||
* the current allocated size |
|||
* |
|||
* Return codes |
|||
* DS_E_OK: length set OK |
|||
* DS_E_INVALID: length to large for current allocation |
|||
*/ |
|||
inline int ds_set_length(DSTRING *p_ds, size_t length) |
|||
{ |
|||
if (length >= p_ds->n_byte_alloc) { |
|||
return DS_E_INVALID; |
|||
} |
|||
p_ds->length = length; |
|||
p_ds->p_buf[p_ds->length] = '\0'; |
|||
return DS_E_OK; |
|||
} /* end of function ds_set_length */ |
|||
|
|||
|
|||
|
|||
/* Sets the length of the data in the buffer to 0. It is equivalent to |
|||
* ds_set_length(p_ds, 0), except that the check for a valid length can |
|||
* be skipped since 0 is always valid. */ |
|||
inline void ds_clear(DSTRING *p_ds) |
|||
{ |
|||
p_ds->length = 0; |
|||
p_ds->p_buf[0] = '\0'; |
|||
} /* end of function ds_clear */ |
|||
|
|||
|
|||
|
|||
/* This function, if successful, returns an allocated buffer with the |
|||
* string to the caller and frees any other resources used by the DSTRING. |
|||
* If the buffer is not allocated and the DS_FREE_MOVE_OPT_FORCE_ALLOC |
|||
* option is not selected, NULL is returned. |
|||
* |
|||
* Parameters |
|||
* p_ds: Address of DSTRING to free |
|||
* opt: Bitwise options |
|||
* DS_FREE_MOVE_OPT_FORCE_ALLOC -- Force allocation in all cases. |
|||
* If fails, the DSTRING is unchanged. |
|||
* DS_FREE_MOVE_OPT_COMPACT -- Resize allocation to minimum size |
|||
* if one already exists. |
|||
* |
|||
* Return values |
|||
* The data string is returned as an allocation to be freed by the caller |
|||
* NULL is returned if either the allocation was stack-based and |
|||
* DS_FREE_MOVE_OPT_FORCE_ALLOC was not selected or if |
|||
* DS_FREE_MOVE_OPT_COMPACT or DS_FREE_MOVE_OPT_FORCE_ALLOC |
|||
* options were given and there was an allocation failure. |
|||
* In any case when NULL is returned, the DSTRING is unchanged |
|||
* on return. |
|||
* |
|||
* Remarks |
|||
* To force freeing of resources if this function fails, either it can |
|||
* be called again with no options or equivalently ds_free() can be used. |
|||
*/ |
|||
#define DS_FREE_MOVE_OPT_FORCE_ALLOC 1 |
|||
#define DS_FREE_MOVE_OPT_COMPACT 2 |
|||
inline char *ds_free_move(DSTRING *p_ds, unsigned int opt) |
|||
{ |
|||
char * const p_buf_active = p_ds->p_buf; |
|||
|
|||
/* If the buffer is from the stack, allocate if requested. Note that the |
|||
* compaction option is meaningless in this case since it is allocated |
|||
* to the minimum size required */ |
|||
if (p_buf_active == p_ds->p_stack_buf) { /* not allocated */ |
|||
if (opt & DS_FREE_MOVE_OPT_FORCE_ALLOC) { |
|||
/* Allocate to minimum size */ |
|||
size_t n_byte_alloc = p_ds->length + 1; |
|||
char * const p_ret = (char *) malloc(n_byte_alloc); |
|||
if (p_ret == (char *) NULL) { |
|||
return (char *) NULL; |
|||
} |
|||
return memcpy(p_ret, p_buf_active, n_byte_alloc); |
|||
} |
|||
return (char *) NULL; |
|||
} |
|||
/* Else allocated */ |
|||
if (opt & DS_FREE_MOVE_OPT_COMPACT) { |
|||
/* Allocate to minimum size */ |
|||
size_t n_byte_alloc = p_ds->length + 1; |
|||
char * const p_ret = (char *) realloc(p_buf_active, n_byte_alloc); |
|||
if (p_ret == (char *) NULL) { |
|||
/* Realloc to smaller size somehow failed! */ |
|||
return (char *) NULL; |
|||
} |
|||
return p_ret; /* Return resized allocation */ |
|||
} |
|||
return p_buf_active; /* Return unchanged */ |
|||
} /* end of function ds_free_move */ |
|||
|
|||
|
|||
|
|||
/* Returns the address of the buffer. The caller should never attempt |
|||
* to free the buffer. With care (not changing the length), it can |
|||
* be modified. */ |
|||
inline char *ds_get_buf(DSTRING *p_ds) |
|||
{ |
|||
return p_ds->p_buf; |
|||
} /* end of function ds_get_buffer */ |
|||
|
|||
|
|||
|
|||
/* Returns the current dstring length */ |
|||
inline size_t ds_get_length(const DSTRING *p_ds) |
|||
{ |
|||
return p_ds->length; |
|||
} /* end of function ds_get_length */ |
|||
|
|||
|
|||
|
|||
/* Returns the allocated dstring buffer size */ |
|||
inline size_t ds_get_buf_size(const DSTRING *p_ds) |
|||
{ |
|||
return p_ds->n_byte_alloc; |
|||
} /* end of function ds_get_buf_size */ |
|||
|
|||
|
|||
|
|||
#ifdef DSTRING_UNIT_TEST |
|||
#include <stdio.h> |
|||
int ds_test(FILE *fp); |
|||
#endif /* UNIT_TEST_DSTRING */ |
|||
|
|||
#endif /* include guard */ |
|||
@ -1,409 +1,539 @@ |
|||
/* ----------------------------------------------------------------- |
|||
FILE: dstring.c |
|||
FILE: dstring.c |
|||
DESCRIPTION:This file contains the routines for manipulating dynamic strings. |
|||
----------------------------------------------------------------- */ |
|||
#include "ngspice/ngspice.h" |
|||
#include <ctype.h> |
|||
#include <stdarg.h> |
|||
#include <stdbool.h> |
|||
#include <stddef.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#include "ngspice/dstring.h" |
|||
|
|||
/* definitions local to this file only */ |
|||
|
|||
/* ********************** TYPE DEFINITIONS ************************* */ |
|||
static int ds_reserve_internal(DSTRING *p_ds, |
|||
size_t n_byte_alloc_opt, size_t n_byte_alloc_min); |
|||
|
|||
/* ********************** STATIC DEFINITIONS ************************* */ |
|||
/* |
|||
*---------------------------------------------------------------------- |
|||
* |
|||
* spice_dstring_init -- |
|||
* |
|||
* Initializes a dynamic string, discarding any previous contents |
|||
* of the string (spice_dstring_free should have been called already |
|||
* if the dynamic string was previously in use). |
|||
* |
|||
* Results: |
|||
* None. |
|||
* |
|||
* Side effects: |
|||
* The dynamic string is initialized to be empty. |
|||
* |
|||
*---------------------------------------------------------------------- |
|||
*/ |
|||
/* Instantiations of dstring functions in case inlining is not performed */ |
|||
int ds_cat_str(DSTRING *p_ds, const char *sz); |
|||
int ds_cat_char(DSTRING *p_ds, char c); |
|||
int ds_cat_ds(DSTRING *p_ds_dst, const DSTRING *p_ds_src); |
|||
int ds_cat_mem(DSTRING *p_ds, const char *p_src, size_t n_char); |
|||
int ds_set_length(DSTRING *p_ds, size_t length); |
|||
void ds_clear(DSTRING *p_ds); |
|||
char *ds_free_move(DSTRING *p_ds, unsigned int opt); |
|||
char *ds_get_buf(DSTRING *p_ds); |
|||
size_t ds_get_length(const DSTRING *p_ds); |
|||
size_t ds_get_buf_size(const DSTRING *p_ds); |
|||
|
|||
void spice_dstring_init(SPICE_DSTRINGPTR dsPtr) |
|||
{ |
|||
dsPtr->string = dsPtr->staticSpace ; |
|||
dsPtr->length = 0 ; |
|||
dsPtr->spaceAvl = SPICE_DSTRING_STATIC_SIZE ; |
|||
dsPtr->staticSpace[0] = '\0'; |
|||
} /* end spice_dstring_init() */ |
|||
|
|||
/* |
|||
*---------------------------------------------------------------------- |
|||
* |
|||
* spice_dstring_append -- |
|||
* |
|||
* Append more characters to the current value of a dynamic string. |
|||
* |
|||
* Results: |
|||
* The return value is a pointer to the dynamic string's new value. |
|||
|
|||
/* This function initalizes a dstring using *p_buf as the initial backing |
|||
* |
|||
* Side effects: |
|||
* Length bytes from string (or all of string if length is less |
|||
* than zero) are added to the current value of the string. Memory |
|||
* gets reallocated if needed to accomodate the string's new size. |
|||
* |
|||
* Notes: char *string; String to append. If length is -1 then |
|||
* this must be null-terminated. |
|||
* INT length; Number of characters from string to append. |
|||
* If < 0, then append all of string, up to null at end. |
|||
* Parameters |
|||
* p_buf: Inital buffer backing the dstring |
|||
* length_string: Length of string in the initial buffer |
|||
* n_byte_data: Length of initial buffer. Must be at least 1 |
|||
* type_buffer: Type of buffer providing initial backing |
|||
* |
|||
*---------------------------------------------------------------------- |
|||
* Return codes |
|||
* DS_E_OK: Init OK |
|||
* DS_E_INVALID: n_byte_data = 0 length_string too long, |
|||
* or unknown buffer type |
|||
*/ |
|||
char *spice_dstring_append(SPICE_DSTRINGPTR dsPtr, const char *string, int length) |
|||
int ds_init(DSTRING *p_ds, char *p_buf, size_t length_string, |
|||
size_t n_byte_buf, ds_buf_type_t type_buffer) |
|||
{ |
|||
int newSize ; /* needed size */ |
|||
char *newString ; /* newly allocated string buffer */ |
|||
char *dst ; /* destination */ |
|||
const char *end ; /* end of string */ |
|||
/* Validate buffer size */ |
|||
if (n_byte_buf == 0) { |
|||
return DS_E_INVALID; |
|||
} |
|||
|
|||
if( length < 0){ |
|||
length = (int) strlen(string) ; |
|||
/* Set current buffer */ |
|||
p_ds->p_buf = p_buf; |
|||
|
|||
/* Set size of current string >= rather than > because this function |
|||
* adds a terminating null */ |
|||
if (length_string >= n_byte_buf) { |
|||
return DS_E_INVALID; |
|||
} |
|||
newSize = length + dsPtr->length ; |
|||
|
|||
/* ----------------------------------------------------------------- |
|||
* Allocate a larger buffer for the string if the current one isn't |
|||
* large enough. Allocate extra space in the new buffer so that there |
|||
* will be room to grow before we have to allocate again. |
|||
----------------------------------------------------------------- */ |
|||
if (newSize >= dsPtr->spaceAvl) { |
|||
dsPtr->spaceAvl = 2 * newSize ; |
|||
newString = TMALLOC(char, dsPtr->spaceAvl) ; |
|||
memcpy(newString, dsPtr->string, (size_t) dsPtr->length) ; |
|||
if (dsPtr->string != dsPtr->staticSpace) { |
|||
txfree(dsPtr->string) ; |
|||
} |
|||
dsPtr->string = newString; |
|||
|
|||
p_ds->n_byte_alloc = n_byte_buf; |
|||
p_ds->length = length_string; |
|||
p_ds->p_buf[length_string] = '\0'; |
|||
|
|||
/* Set stack buffer */ |
|||
if (type_buffer == ds_buf_type_stack) { |
|||
p_ds->p_stack_buf = p_buf; |
|||
p_ds->n_byte_stack_buf = n_byte_buf; |
|||
} |
|||
else if (type_buffer == ds_buf_type_heap) { |
|||
p_ds->p_stack_buf = (char *) NULL; |
|||
p_ds->n_byte_stack_buf = 0; |
|||
} |
|||
else { /* unknown buffer type */ |
|||
return DS_E_INVALID; |
|||
} |
|||
|
|||
return DS_E_OK; |
|||
} /* end of function ds_init */ |
|||
|
|||
/* ----------------------------------------------------------------- |
|||
* Copy the new string into the buffer at the end of the old |
|||
* one. |
|||
----------------------------------------------------------------- */ |
|||
for( dst = dsPtr->string + dsPtr->length, end = string+length; |
|||
string < end; string++, dst++) { |
|||
*dst = *string ; |
|||
|
|||
|
|||
/* This function frees all memory used by the dstring. After calling this |
|||
* function, the dstring should not be used again. */ |
|||
void ds_free(DSTRING *p_ds) |
|||
{ |
|||
if (p_ds->p_buf != p_ds->p_stack_buf) { |
|||
free((void *) p_ds->p_buf); |
|||
} |
|||
*dst = '\0' ; |
|||
dsPtr->length += length ; |
|||
} /* end of function ds_free */ |
|||
|
|||
return(dsPtr->string) ; |
|||
|
|||
} /* end spice_dstring_append() */ |
|||
|
|||
/* |
|||
*---------------------------------------------------------------------- |
|||
* |
|||
* spice_dstring_append_lower -- |
|||
* |
|||
* Append more characters converted to lower case to the current |
|||
* value of a dynamic string. |
|||
* |
|||
* Results: |
|||
* The return value is a pointer to the dynamic string's new value. |
|||
* |
|||
* Side effects: |
|||
* Length bytes from string (or all of string if length is less |
|||
* than zero) are added to the current value of the string. Memory |
|||
* gets reallocated if needed to accomodate the string's new size. |
|||
* |
|||
* Notes: char *string; String to append. If length is -1 then |
|||
* this must be null-terminated. |
|||
* INT length; Number of characters from string to append. |
|||
* If < 0, then append all of string, up to null at end. |
|||
* |
|||
*---------------------------------------------------------------------- |
|||
*/ |
|||
char *spice_dstring_append_lower(SPICE_DSTRINGPTR dsPtr, const char *string, int length) |
|||
/* Concatenate string */ |
|||
int ds_cat_str_case(DSTRING *p_ds, const char *sz, ds_case_t case_type) |
|||
{ |
|||
return ds_cat_mem_case(p_ds, sz, strlen(sz), case_type); |
|||
} /* end of function ds_cat_str_case */ |
|||
|
|||
|
|||
|
|||
/* Concatenate character */ |
|||
int ds_cat_char_case(DSTRING *p_ds, char c, ds_case_t case_type) |
|||
{ |
|||
return ds_cat_mem_case(p_ds, &c, 1, case_type); |
|||
} /* end of function ds_cat_char_case */ |
|||
|
|||
|
|||
|
|||
/* Concatenate another dstring */ |
|||
int ds_cat_ds_case(DSTRING *p_ds_dst, const DSTRING *p_ds_src, |
|||
ds_case_t case_type) |
|||
{ |
|||
return ds_cat_mem_case(p_ds_dst, p_ds_src->p_buf, p_ds_src->length, |
|||
case_type); |
|||
} /* end of function ds_cat_ds_case */ |
|||
|
|||
|
|||
|
|||
/* General concatenation of a memory buffer. A terminating null is added. */ |
|||
int ds_cat_mem_case(DSTRING *p_ds, const char *p_src, size_t n_char, |
|||
ds_case_t type_case) |
|||
{ |
|||
int newSize ; /* needed size */ |
|||
char *newString ; /* newly allocated string buffer */ |
|||
char *dst ; /* destination */ |
|||
const char *end ; /* end of string */ |
|||
/* Resize buffer if necessary. Double required size, if available, |
|||
* to reduce the number of allocations */ |
|||
const size_t length_new = p_ds->length + n_char; |
|||
const size_t n_byte_needed = length_new + 1; |
|||
if (n_byte_needed > p_ds->n_byte_alloc) { |
|||
if (ds_reserve_internal(p_ds, |
|||
2 * n_byte_needed, n_byte_needed) == DS_E_NO_MEMORY) { |
|||
return DS_E_NO_MEMORY; |
|||
} |
|||
} |
|||
|
|||
if( length < 0){ |
|||
length = (int) strlen(string) ; |
|||
/* For "as-is" can simply memcpy */ |
|||
if (type_case == ds_case_as_is) { |
|||
char *p_dst = p_ds->p_buf + p_ds->length; |
|||
(void) memcpy(p_dst, p_src, n_char); |
|||
p_dst += n_char; |
|||
*p_dst = '\0'; |
|||
p_ds->length = length_new; |
|||
return DS_E_OK; |
|||
} |
|||
newSize = length + dsPtr->length ; |
|||
|
|||
/* ----------------------------------------------------------------- |
|||
* Allocate a larger buffer for the string if the current one isn't |
|||
* large enough. Allocate extra space in the new buffer so that there |
|||
* will be room to grow before we have to allocate again. |
|||
----------------------------------------------------------------- */ |
|||
if (newSize >= dsPtr->spaceAvl) { |
|||
dsPtr->spaceAvl = 2 * newSize ; |
|||
newString = TMALLOC(char, dsPtr->spaceAvl) ; |
|||
memcpy(newString, dsPtr->string, (size_t) dsPtr->length) ; |
|||
if (dsPtr->string != dsPtr->staticSpace) { |
|||
txfree(dsPtr->string) ; |
|||
|
|||
/* For lowercasing, work char by char */ |
|||
if (type_case == ds_case_lower) { |
|||
char *p_dst = p_ds->p_buf + p_ds->length; |
|||
char *p_dst_end = p_dst + n_char; |
|||
for ( ; p_dst < p_dst_end; p_dst++, p_src++) { |
|||
*p_dst = (char) tolower(*p_src); |
|||
} |
|||
dsPtr->string = newString; |
|||
*p_dst_end = '\0'; |
|||
p_ds->length = length_new; |
|||
return DS_E_OK; |
|||
} |
|||
|
|||
/* ----------------------------------------------------------------- |
|||
* Copy the new string into the buffer at the end of the old |
|||
* one. |
|||
----------------------------------------------------------------- */ |
|||
for( dst = dsPtr->string + dsPtr->length, end = string+length; |
|||
string < end; string++, dst++) { |
|||
if( isupper_c(*string) ) { |
|||
*dst = tolower_c(*string) ; |
|||
} else { |
|||
*dst = *string ; |
|||
/* Uppercasing done like lowercasing. Note that it would be possible to |
|||
* use a function pointer and select either tolower() or toupper() based |
|||
* on type_case, but doing so may degrade performance by inhibiting |
|||
* inlining. */ |
|||
if (type_case == ds_case_upper) { |
|||
char *p_dst = p_ds->p_buf + p_ds->length; |
|||
char *p_dst_end = p_dst + n_char; |
|||
for ( ; p_dst < p_dst_end; p_dst++, p_src++) { |
|||
*p_dst = (char) toupper(*p_src); |
|||
} |
|||
*p_dst_end = '\0'; |
|||
p_ds->length = length_new; |
|||
return DS_E_OK; |
|||
} |
|||
*dst = '\0' ; |
|||
dsPtr->length += length ; |
|||
|
|||
return(dsPtr->string) ; |
|||
return DS_E_INVALID; /* unknown case type */ |
|||
} /* end of function ds_cat_mem_case */ |
|||
|
|||
} /* end spice_dstring_append_lower() */ |
|||
|
|||
/* ----------------------------------------------------------------- |
|||
* Function: add character c to dynamic string dstr_p. |
|||
* ----------------------------------------------------------------- */ |
|||
char *spice_dstring_append_char( SPICE_DSTRINGPTR dstr_p, char c) |
|||
{ |
|||
return spice_dstring_append( dstr_p, &c, 1 ) ; |
|||
} /* end spice_dstring_append_char() */ |
|||
|
|||
static int spice_format_length( const char *fmt, va_list args ) |
|||
/* Ensure minimum internal buffer size */ |
|||
int ds_reserve(DSTRING *p_ds, size_t n_byte_alloc) |
|||
{ |
|||
int i ; /* integer */ |
|||
int len ; /* length of format */ |
|||
int size_format ; /* width of field */ |
|||
int found_special ; /* look for special characters */ |
|||
char *s ; /* string */ |
|||
double d ; |
|||
|
|||
/* ----------------------------------------------------------------- |
|||
* First find length of buffer. |
|||
----------------------------------------------------------------- */ |
|||
len = 0 ; |
|||
while(fmt && *fmt){ |
|||
if( *fmt == '%' ){ |
|||
fmt++ ; |
|||
if( *fmt == '%' ){ |
|||
len++ ; |
|||
} else { |
|||
/* ----------------------------------------------------------------- |
|||
* We have a real formatting character, loop until we get a special |
|||
* character. |
|||
----------------------------------------------------------------- */ |
|||
if( *fmt == '.' || *fmt == '-' ){ |
|||
fmt++ ; /* skip over these characters */ |
|||
} |
|||
size_format = atoi(fmt) ; |
|||
if( size_format > 0 ){ |
|||
len += size_format ; |
|||
} |
|||
found_special = FALSE ; |
|||
for( ; fmt && *fmt ; fmt++ ){ |
|||
switch( *fmt ){ |
|||
case 's': |
|||
s = va_arg(args, char *) ; |
|||
if( s ){ |
|||
len += (int) strlen(s) ; |
|||
} |
|||
found_special = TRUE ; |
|||
break ; |
|||
case 'i': |
|||
case 'd': |
|||
case 'o': |
|||
case 'x': |
|||
case 'X': |
|||
case 'u': |
|||
i = va_arg(args, int) ; |
|||
len += 10 ; |
|||
found_special = TRUE ; |
|||
break ; |
|||
case 'c': |
|||
i = va_arg(args, int) ; |
|||
len++ ; |
|||
found_special = TRUE ; |
|||
break ; |
|||
case 'f': |
|||
case 'e': |
|||
case 'F': |
|||
case 'g': |
|||
case 'G': |
|||
d = va_arg(args, double) ; |
|||
len += 35 ; |
|||
found_special = TRUE ; |
|||
break ; |
|||
default: |
|||
; |
|||
} /* end switch() */ |
|||
|
|||
if( found_special ){ |
|||
break ; |
|||
} |
|||
} |
|||
} |
|||
} else { |
|||
len++ ; |
|||
} |
|||
fmt++ ; |
|||
} /* end while() */ |
|||
|
|||
return(len) ; |
|||
|
|||
} /* end Ymessage_format_length() */ |
|||
|
|||
|
|||
char *spice_dstring_print( SPICE_DSTRINGPTR dsPtr, const char *format, ... ) |
|||
{ |
|||
va_list args ; |
|||
int format_len ; /* length of format */ |
|||
int length ; /* new length */ |
|||
int orig_length ; /* original length of buffer */ |
|||
char *buffer ; /* proper length of buffer */ |
|||
|
|||
/* ----------------------------------------------------------------- |
|||
* First get the length of the buffer needed. |
|||
----------------------------------------------------------------- */ |
|||
va_start( args, format ) ; |
|||
format_len = spice_format_length(format, args) ; |
|||
va_end(args) ; |
|||
|
|||
/* ----------------------------------------------------------------- |
|||
* Next allocate the proper buffer size. |
|||
----------------------------------------------------------------- */ |
|||
orig_length = dsPtr->length ; |
|||
length = orig_length + format_len + 1 ; |
|||
buffer = spice_dstring_setlength( dsPtr, length) ; |
|||
|
|||
/* ----------------------------------------------------------------- |
|||
* Convert the format. |
|||
----------------------------------------------------------------- */ |
|||
va_start( args, format ) ; |
|||
if( format ){ |
|||
vsprintf( buffer + orig_length, format, args ) ; |
|||
dsPtr->length = (int) strlen(buffer) ; |
|||
} else { |
|||
buffer = NULL ; |
|||
/* Return if buffer already large enough */ |
|||
if (p_ds->n_byte_alloc >= n_byte_alloc) { |
|||
return DS_E_OK; |
|||
} |
|||
va_end(args) ; |
|||
return( buffer ) ; |
|||
|
|||
} /* end spice_dstring_print() */ |
|||
|
|||
/* |
|||
*---------------------------------------------------------------------- |
|||
* |
|||
* _spice_dstring_setlength -- |
|||
return ds_reserve_internal(p_ds, n_byte_alloc, 0); |
|||
} /* end of function ds_reserve */ |
|||
|
|||
|
|||
|
|||
/* This function resizes the buffer for the string and handles freeing |
|||
* the original alloction, if necessary. It is assumed that the requested |
|||
* size or sizes are larger than the current size. |
|||
* |
|||
* Change the length of a dynamic string. This can cause the |
|||
* string to either grow or shrink, depending on the value of |
|||
* length. |
|||
* Parameters |
|||
* p_ds: Dstring pointer |
|||
* n_byte_alloc_opt: Optimal alloction amount |
|||
* n_byte_alloc_min: Absolute minimum allocation amount or 0 if no |
|||
* smaller amount can be allocated |
|||
* |
|||
* Results: |
|||
* Returns the current string buffer. |
|||
* Return codes |
|||
* DS_E_OK: At least the minimum allocation was performed |
|||
* DS_E_NO_MEMORY: Unable to resize the buffer */ |
|||
static int ds_reserve_internal(DSTRING *p_ds, |
|||
size_t n_byte_alloc_opt, size_t n_byte_alloc_min) |
|||
{ |
|||
size_t n_byte_alloc = n_byte_alloc_opt; |
|||
/* Allocate. First try (larger) optimal size, and gradually fall back |
|||
* to min size if that fails and one was provided. */ |
|||
char * p_buf_new; |
|||
if (n_byte_alloc_min == 0) { |
|||
n_byte_alloc_min = n_byte_alloc_opt; |
|||
} |
|||
for ( ; ; ) { |
|||
if ((p_buf_new = (char *) malloc(n_byte_alloc)) != (char *) NULL) { |
|||
break; /* Allocated OK */ |
|||
} |
|||
|
|||
if (n_byte_alloc == n_byte_alloc_min) { /* min alloc failed */ |
|||
return DS_E_NO_MEMORY; |
|||
} |
|||
|
|||
if ((n_byte_alloc /= 2) < n_byte_alloc_min) { /* last try */ |
|||
n_byte_alloc = n_byte_alloc_min; |
|||
} |
|||
} /* end of loop trying smaller allocations */ |
|||
|
|||
/* Copy to the new buffer */ |
|||
(void) memcpy(p_buf_new, p_ds->p_buf, p_ds->length + 1); |
|||
|
|||
/* If there already was a dynamic allocation, free it */ |
|||
if (p_ds->p_buf != p_ds->p_stack_buf) { |
|||
free((void *) p_ds->p_buf); |
|||
} |
|||
|
|||
/* Assign new active buffer and its size */ |
|||
p_ds->p_buf = p_buf_new; |
|||
p_ds->n_byte_alloc = n_byte_alloc; |
|||
|
|||
return DS_E_OK; |
|||
} /* end of function ds_reserve_nocheck */ |
|||
|
|||
|
|||
|
|||
/* Concatenate the result of a printf-style format |
|||
* |
|||
* Side effects: |
|||
* The length of dsPtr is changed to length but a null byte is not |
|||
* stored at that position in the string. Use spice_dstring_setlength |
|||
* for that function. If length is larger |
|||
* than the space allocated for dsPtr, then a panic occurs. |
|||
* Return codes as for ds_cat_vprintf */ |
|||
int ds_cat_printf(DSTRING *p_ds, const char *sz_fmt, ...) |
|||
{ |
|||
va_list p_arg; |
|||
va_start(p_arg, sz_fmt); |
|||
const int xrc = ds_cat_vprintf(p_ds, sz_fmt, p_arg); |
|||
va_end(p_arg); |
|||
return xrc; |
|||
} /* end of function ds_cat_printf */ |
|||
|
|||
|
|||
|
|||
/* Concatenate the result of a printf-style format using va_list |
|||
* |
|||
*---------------------------------------------------------------------- |
|||
* Return codes |
|||
* DS_E_OK: Formatted OK |
|||
* DS_E_NO_MEMORY: Unable to allocate memory to resize buffer |
|||
* DS_E_INVALID: Invalid formatter / data |
|||
*/ |
|||
|
|||
char *_spice_dstring_setlength(SPICE_DSTRINGPTR dsPtr,int length) |
|||
int ds_cat_vprintf(DSTRING *p_ds, const char *sz_fmt, va_list p_arg) |
|||
{ |
|||
char *newString ; |
|||
/* Make a copy of the argument list in case need to format more than |
|||
* once */ |
|||
va_list p_arg2; |
|||
va_copy(p_arg2, p_arg); |
|||
const size_t n_byte_free = p_ds->n_byte_alloc - p_ds->length; |
|||
char * const p_dst = p_ds->p_buf + p_ds->length; |
|||
const int rc = vsnprintf(p_dst, n_byte_free, sz_fmt, p_arg); |
|||
if (rc < 0) { /* Check for formatting error */ |
|||
return DS_E_INVALID; |
|||
} |
|||
|
|||
if (length < 0) { |
|||
length = 0 ; |
|||
/* Else check for buffer large enough and set length if it is */ |
|||
if (rc < n_byte_free) { |
|||
p_ds->length += rc; |
|||
return DS_E_OK; |
|||
} |
|||
if (length >= dsPtr->spaceAvl) { |
|||
|
|||
dsPtr->spaceAvl = length+1; |
|||
newString = TMALLOC(char, dsPtr->spaceAvl) ; |
|||
/* ----------------------------------------------------------------- |
|||
* SPECIAL NOTE: must use memcpy, not strcpy, to copy the string |
|||
* to a larger buffer, since there may be embedded NULLs in the |
|||
* string in some cases. |
|||
----------------------------------------------------------------- */ |
|||
memcpy(newString, dsPtr->string, (size_t) dsPtr->length) ; |
|||
if( dsPtr->string != dsPtr->staticSpace ) { |
|||
txfree(dsPtr->string) ; |
|||
} |
|||
dsPtr->string = newString ; |
|||
|
|||
/* Else buffer too small, so resize and format again */ |
|||
{ |
|||
/* Double required size to avoid excessive allocations +1 for |
|||
* null, which is not included in the count returned by snprintf */ |
|||
const size_t n_byte_alloc_min = p_ds->length + rc + 1; |
|||
if (ds_reserve_internal(p_ds, |
|||
2 * n_byte_alloc_min, n_byte_alloc_min) == DS_E_NO_MEMORY) { |
|||
/* vsnprintf may have written bytes to the buffer. |
|||
* Ensure that dstring in a consistent state by writing |
|||
* a null at the length of the string */ |
|||
p_ds->p_buf[p_ds->length] = '\0'; |
|||
return DS_E_NO_MEMORY; |
|||
} |
|||
const size_t n_byte_free2 = p_ds->n_byte_alloc - p_ds->length; |
|||
char * const p_dst2 = p_ds->p_buf + p_ds->length; |
|||
const int rc2 = vsnprintf(p_dst2, n_byte_free2, sz_fmt, p_arg2); |
|||
if (rc2 < 0) { /* Check for formatting error */ |
|||
/* vsnprintf may have written bytes to the buffer. |
|||
* Ensure that dstring in a consistent state by writing |
|||
* a null at the length of the string */ |
|||
p_ds->p_buf[p_ds->length] = '\0'; |
|||
return DS_E_INVALID; |
|||
} |
|||
|
|||
/* Else update length. No need to check buffer size since it was |
|||
* sized to fit the string. */ |
|||
p_ds->length += rc2; |
|||
return DS_E_OK; |
|||
} |
|||
dsPtr->length = length ; |
|||
return(dsPtr->string) ; |
|||
} /* end of function ds_cat_vprintf */ |
|||
|
|||
} /* end _spice_dstring_setlength() */ |
|||
|
|||
|
|||
/* |
|||
*---------------------------------------------------------------------- |
|||
* |
|||
* spice_dstring_setlength -- |
|||
* |
|||
* Change the length of a dynamic string. This can cause the |
|||
* string to either grow or shrink, depending on the value of |
|||
* length. |
|||
* |
|||
* Results: |
|||
* Returns the current string buffer. |
|||
* |
|||
* Side effects: |
|||
* The length of dsPtr is changed to length and a null byte is |
|||
* stored at that position in the string. If length is larger |
|||
* than the space allocated for dsPtr, then a panic occurs. |
|||
|
|||
|
|||
/* Reallocate/free to eliminate unused buffer space. |
|||
* |
|||
*---------------------------------------------------------------------- |
|||
*/ |
|||
* Return codes |
|||
* DS_E_OK: Compacted OK |
|||
* DS_E_NO_MEMORY: Compaction failed, but dstring still valid */ |
|||
int ds_compact(DSTRING *p_ds) |
|||
{ |
|||
const size_t n_byte_alloc_min = p_ds->length + 1; |
|||
|
|||
/* If the string is in the stack buffer, there is nothing to do */ |
|||
if (p_ds->p_stack_buf == p_ds->p_buf) { |
|||
return DS_E_OK; |
|||
} |
|||
|
|||
/* Else if the string will fit in the stack buffer, copy it there and |
|||
* free the allocation. */ |
|||
if (p_ds->n_byte_stack_buf >= n_byte_alloc_min) { |
|||
(void) memcpy(p_ds->p_stack_buf, p_ds->p_buf, n_byte_alloc_min); |
|||
free((void *) p_ds->p_buf); |
|||
p_ds->p_buf = p_ds->p_stack_buf; |
|||
p_ds->n_byte_alloc = p_ds->n_byte_stack_buf; |
|||
return DS_E_OK; |
|||
} |
|||
|
|||
/* Else if the heap buffer is the minimum size, there is nothng to do */ |
|||
if (n_byte_alloc_min == p_ds->n_byte_alloc) { |
|||
return DS_E_OK; |
|||
} |
|||
|
|||
/* Else realloc the heap buffer */ |
|||
{ |
|||
void *p = realloc(p_ds->p_buf, n_byte_alloc_min); |
|||
if (p == NULL) { |
|||
return DS_E_NO_MEMORY; |
|||
} |
|||
p_ds->p_buf = (char *) p; |
|||
p_ds->n_byte_alloc = n_byte_alloc_min; |
|||
return DS_E_OK; |
|||
} |
|||
} /* end of function ds_compact */ |
|||
|
|||
|
|||
|
|||
char *spice_dstring_setlength(SPICE_DSTRINGPTR dsPtr,int length) |
|||
#ifdef DSTRING_UNIT_TEST |
|||
#if defined (_WIN32) && !defined(CONSOLE) |
|||
#include "ngspice/wstdio.h" |
|||
#endif |
|||
static void ds_print_info(DSTRING *p_ds, FILE *fp, const char *sz_id); |
|||
static int ds_test_from_macro(FILE *fp); |
|||
static int ds_test_from_stack(FILE *fp); |
|||
static int ds_test_from_heap(FILE *fp); |
|||
static int ds_test1(DSTRING *p_ds, FILE *fp); |
|||
|
|||
|
|||
int ds_test(FILE *fp) |
|||
{ |
|||
char *str_p ; /* newly create string */ |
|||
if (ds_test_from_macro(fp) != 0) { /* create from macro and run test */ |
|||
return -1; |
|||
} |
|||
if (ds_test_from_stack(fp) != 0) { /* create from stack */ |
|||
return -1; |
|||
} |
|||
if (ds_test_from_heap(fp) != 0) { /* create from heap */ |
|||
return -1; |
|||
} |
|||
|
|||
str_p = _spice_dstring_setlength( dsPtr,length) ; |
|||
str_p[length] = '\0' ; |
|||
return( str_p ) ; |
|||
return 0; |
|||
} /* end of function ds_test */ |
|||
|
|||
|
|||
|
|||
/* Run tests from a macro-created dstring */ |
|||
static int ds_test_from_macro(FILE *fp) |
|||
{ |
|||
DS_CREATE(ds, 10); |
|||
(void) fprintf(fp, "Macro initialization\n"); |
|||
return ds_test1(&ds, fp); |
|||
} /* end of function ds_test_from_macro */ |
|||
|
|||
|
|||
|
|||
/* Run tests from a manually created stack-backed dstring */ |
|||
static int ds_test_from_stack(FILE *fp) |
|||
{ |
|||
static char p_buf[30] = "Hello World"; |
|||
DSTRING ds; |
|||
(void) fprintf(fp, "Stack initialization\n"); |
|||
(void) ds_init(&ds, p_buf, 11, sizeof p_buf, ds_buf_type_stack); |
|||
return ds_test1(&ds, fp); |
|||
} /* end of function ds_test_from_stack */ |
|||
|
|||
} /* end spice_dstring_setlength() */ |
|||
|
|||
/* |
|||
*---------------------------------------------------------------------- |
|||
* |
|||
* spice_dstring_free -- |
|||
* |
|||
* Frees up any memory allocated for the dynamic string and |
|||
* reinitializes the string to an empty state. |
|||
* |
|||
* Results: |
|||
* None. |
|||
* |
|||
* Side effects: |
|||
* The previous contents of the dynamic string are lost, and |
|||
* the new value is an empty string. |
|||
* |
|||
*---------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
void spice_dstring_free(SPICE_DSTRINGPTR dsPtr) |
|||
/* Run tests from a heap-backed dstring */ |
|||
static int ds_test_from_heap(FILE *fp) |
|||
{ |
|||
if (dsPtr->string != dsPtr->staticSpace) { |
|||
txfree(dsPtr->string) ; |
|||
char *p_buf = (char *) malloc(25); |
|||
if (p_buf == (char *) NULL) { |
|||
return -1; |
|||
} |
|||
dsPtr->string = dsPtr->staticSpace ; |
|||
dsPtr->length = 0 ; |
|||
dsPtr->spaceAvl = SPICE_DSTRING_STATIC_SIZE; |
|||
dsPtr->staticSpace[0] = '\0' ; |
|||
(void) memcpy(p_buf, "Heap", 4); |
|||
DSTRING ds; |
|||
(void) ds_init(&ds, p_buf, 4, 25, ds_buf_type_heap); |
|||
(void) fprintf(fp, "Heap initialization\n"); |
|||
return ds_test1(&ds, fp); |
|||
} /* end of function ds_test_from_heap */ |
|||
|
|||
|
|||
|
|||
static int ds_test1(DSTRING *p_ds, FILE *fp) |
|||
{ |
|||
/* Print info on entry */ |
|||
ds_print_info(p_ds, fp, "On entry to ds_test1\n"); |
|||
|
|||
int i; |
|||
for (i = 0; i < 10; i++) { |
|||
if (ds_cat_str(p_ds, "Abc") != 0) { |
|||
(void) fprintf(fp, "Unable to cat string %d.\n", i); |
|||
return -1; |
|||
} |
|||
if (ds_cat_str_case(p_ds, "Abc", ds_case_as_is) != 0) { |
|||
(void) fprintf(fp, "Unable to cat string as-is %d.\n", i); |
|||
return -1; |
|||
} |
|||
if (ds_cat_str_case(p_ds, "Abc", ds_case_upper) != 0) { |
|||
(void) fprintf(fp, "Unable to cat string upper %d.\n", i); |
|||
return -1; |
|||
} |
|||
if (ds_cat_str_case(p_ds, "Abc", ds_case_lower) != 0) { |
|||
(void) fprintf(fp, "Unable to cat string lower %d.\n", i); |
|||
return -1; |
|||
} |
|||
if (ds_cat_char(p_ds, 'z') != 0) { |
|||
(void) fprintf(fp, "Unable to cat char %d.\n", i); |
|||
return -1; |
|||
} |
|||
if (ds_cat_char_case(p_ds, 'z', ds_case_as_is) != 0) { |
|||
(void) fprintf(fp, "Unable to cat char as-is %d.\n", i); |
|||
return -1; |
|||
} |
|||
if (ds_cat_char_case(p_ds, 'z', ds_case_upper) != 0) { |
|||
(void) fprintf(fp, "Unable to cat char upper %d.\n", i); |
|||
return -1; |
|||
} |
|||
if (ds_cat_char_case(p_ds, 'Z', ds_case_lower) != 0) { |
|||
(void) fprintf(fp, "Unable to cat char lower %d.\n", i); |
|||
return -1; |
|||
} |
|||
|
|||
if (ds_cat_mem(p_ds, "Zyxw", 4) != 0) { |
|||
(void) fprintf(fp, "Unable to cat string %d.\n", i); |
|||
return -1; |
|||
} |
|||
if (ds_cat_mem_case(p_ds, "Zyxw", 4, ds_case_as_is) != 0) { |
|||
(void) fprintf(fp, "Unable to cat string as-is %d.\n", i); |
|||
return -1; |
|||
} |
|||
if (ds_cat_mem_case(p_ds, "Zyxw", 4, ds_case_upper) != 0) { |
|||
(void) fprintf(fp, "Unable to cat string upper %d.\n", i); |
|||
return -1; |
|||
} |
|||
if (ds_cat_mem_case(p_ds, "Zyxw", 4, ds_case_lower) != 0) { |
|||
(void) fprintf(fp, "Unable to cat string lower %d.\n", i); |
|||
return -1; |
|||
} |
|||
|
|||
if (ds_cat_printf(p_ds, "--- And finally a formatted %s (%d)", |
|||
"string", i) != 0) { |
|||
(void) fprintf(fp, "Unable to cat formatted string %d.\n", i); |
|||
return -1; |
|||
} |
|||
|
|||
/* Print info after cats */ |
|||
ds_print_info(p_ds, fp, "After appending strings"); |
|||
|
|||
/* Truncate the string */ |
|||
if (ds_set_length(p_ds, i * (size_t) 10) != 0) { |
|||
(void) fprintf(fp, "Unable to set size %d.\n", i); |
|||
return -1; |
|||
} |
|||
|
|||
/* Print info after truncation */ |
|||
ds_print_info(p_ds, fp, "After setting length"); |
|||
|
|||
/* Compact the string */ |
|||
if (ds_compact(p_ds) != 0) { |
|||
(void) fprintf(fp, "Unable to compact %d.\n", i); |
|||
return -1; |
|||
} |
|||
|
|||
/* Print info after compaction */ |
|||
ds_print_info(p_ds, fp, "After compacting the string"); |
|||
} /* end of loop over tests */ |
|||
|
|||
ds_free(p_ds); /* free buffer if allocated */ |
|||
|
|||
return 0; |
|||
} /* end of funtion ds_test */ |
|||
|
|||
|
|||
|
|||
/* Print some info about the DSTRING */ |
|||
static void ds_print_info(DSTRING *p_ds, FILE *fp, const char *sz_id) |
|||
{ |
|||
(void) fprintf(fp, "%s: length = %zu; " |
|||
"allocated buffer size = %zu; value = \"%s\"; " |
|||
"address of active buffer = %p; " |
|||
"address of stack buffer = %p; " |
|||
"size of stack buffer = %zu\n", |
|||
sz_id, |
|||
ds_get_length(p_ds), ds_get_buf_size(p_ds), |
|||
ds_get_buf(p_ds), ds_get_buf(p_ds), |
|||
p_ds->p_stack_buf, p_ds->n_byte_stack_buf); |
|||
} /* end of function ds_print_info */ |
|||
|
|||
|
|||
|
|||
#endif /* DSTRING_UNIT_TEST */ |
|||
|
|||
|
|||
|
|||
} /* end spice_dstring_free() */ |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue